一、Java中一元加号的作用是什么?

Java中一元减号-是用于转变数据的符号,而+除了与-对应,它唯一的作用就是将较小类型的操作数提升为int类型,例如将byteshortchar提升为int

public class Example {
    public static void main(String[] args) {
        short s = 1;
        char c = 'c';
        byte b = 2;
        
        print(s);
        print(+s);
        
        print(c);
        print(+c);//输出99,即字符c对应的ASSII码
        
        print(b);
        print(+b);
    }
    
    public static void print(int i) {
        System.out.println("int:"+i);
    }
    
    public static void print(byte i) {
        System.out.println("byte:"+i);
    }
    
    public static void print(short i) {
        System.out.println("short:"+i);
    }
    
    public static void print(char i) {
        System.out.println("char:"+i);
    }
}

二、由private修饰的方法和属性能不能被子类继承?

不能。换言之,就算能继承了也不能使用,而继承的意义就是为了使用。

三、参数数量可变的方法

java中可以写参数数量可变的方法,例如:

public class ArgMoreTest {
     public static void main(String args[]) {
          ArgMoreTest.printStr("abc");
          ArgMoreTest.printStr("abc",123,"你好");
     }
     
     public static void printStr(String title,Object...args) {
          System.out.println(title);
          for (Object object : args) {
              System.out.println(object.toString());
          }
     }
}

其实main方法中的参数也可以写成String...args,代表的是命令行参数,可以多个,例如执行命令java ClassTest h c的时候,其中的h就会传递给args[0]c就会传递给args[1]

四、ArrayList的应用

  • 在初始化时指定容量为100:ArrayList<Object> a = new ArrayList<Object>(100);
  • 除非往里面放元素否则a.size()为0。
  • 如果知道元素个数,则可以使用a.ensureCapacity(100)来指定初始化数组大小,这样在100个元素内,可以减少因为空间不够虚拟机自动扩充ArrayList的操作。
  • 最后,如果知道元素个数不再变化,则可以用a.trimToSize();来将储存区域的大小调整为当前元素数量所需要的存储空间数目,垃圾回收器将回收多余的存储空间。

五、自动拆箱和自动装箱

装箱和拆箱是编译器认可的,而不是虚拟机。编译器在生成类的字节码时,插入必要的方法调用。虚拟机只是执行字节码。
自动装箱:

ArrayList<Integer> a = new ArrayList<Integer>();
a.add(1);//自动装箱,相当于a.add(Integer.valueOf(1));

自动拆箱:

Integer i = new Integet();
int j = i;//自动拆箱,相当于int j = i.intValue();

如果在一个表达式中混合使用Integer和Double类型,Integer值就会拆箱,提升为double,再装箱为Double。
例如:

Integer n = 1;
Double x = 2.0;
System.out.print(true?n:x);//n先被提升为double,又装箱成Double,打印出来1.0。

六、枚举

  • 枚举常量的比较使用==而不是equals
  • 每个枚举类型都有一个静态的values方法,它将返回包含所有枚举值的数组
  • ordinal方法返回enum声明中枚举常量的位置,位置从0开始计数

七、反射

  • 通过对象获取类名:String className = obj.getClass().getName();
  • 通过类名获取Class对象:Class a = Class.forName("java.util.Random")forName只有在是类名或接口名时才能执
  • 使用forNamenewInstance可以通过一个字符串中的类名来创建一个对象:String s = "java.util.Random";Object m = Class.forName(s).newInstance();
  • 以上的方式使用默认的构造器创建对象。如果想要传入参数,则应该使用Constructor类中的newInstance方法。

八、多态性

除非有足够的理由使用多态性,否则应该把所有的方法都声明为final。如果一个方法没有被覆盖并且很短,编译器能对其进行优化处理,这个过程被称为内联。这是一项很有意义的改进, 这是由于CPU 在处理调用方法的指令时, 使用的分支转移会扰乱预取指令的策略, 所以,这被视为不受欢迎的。然而, 如果getName 在另外一个类中被覆盖, 那么编译器就无法知道覆盖的代码将会做什么操作, 因此也就不能对它进行内联处理了。幸运的是, 虚拟机中的即时编译器比传统编译器的处理能力强得多。这种编译器可以准确地知道类之间的继承关系, 并能够检测出类中是否真正地存在覆盖给定的方法。如果方法很简短、被频繁调用且没有真正地被覆盖, 那么即时编译器就会将这个方法进行内联处理。如果虚拟机加载了另外一个子类,而在这个子类中包含了对内联方法的覆盖, 那么将会发生什么情况呢? 优化器将取消对覆盖方法的内联。这个过程很慢, 但却很少发生。

文章目录