记录一下java学习过程的重要知识点
out: for (int i = 0; i < 10; i++) {
System.out.print("i = " + i + "\t");
for (int j = 0; j < 5; j++) {
System.out.print("j =" + j + "\t");
if (j == 3) {
break out;
}
}
System.out.print("\n");
}
7.当一个方法执行时,每个方法都会建立自己的内存栈,在这个方法内定义的变量将会逐个放入这块栈内存中,随着方法的执行结束,这个方法的内存栈也将自然销毁。 因此,所有在方法中定义的局部变量都是放在栈内存中的;在程序中创建一个对象时,这个对象将被保存到运行时数据区中,以便反复利用(因为对象的创建成本通常较大),这个运行时数据区就是堆内存。堆内存中的对象不会随着方法的结束而销毁,即使方法结束后,这个对象还可能被另一个引用变量所引用(在方法的参数传递时很常见),则这个对象依然不会被销毁。只有当一个对象没有任何引用变量引用它时,系统的垃圾回收器才会在合适的时候回收它。
8.static修饰符的真正作用就是用于区分成员变量、方法、内部类、初始化块这四种成员到底属于类本身还是属于实例。在类中定义的成员,static相当于一个标志,有static修饰的成员属于类本身,没有static修饰的成员属于该类的实例。
10.如果同一个类中定义了test(String... books)方法,同时还定义了一个test(String)方法,则test(String... books)方法的books不可能通过直接传入一个字符串参数来调用,如果只传入一个参数,系统会执行重载的test(String)方法。如果需要调用test(String... books)方法,又只想传入一个字符串参数,则可采用传入字符串数组的形式。
11.如果一个Java源文件里定义的所有类都没有使用public修饰,则这个源文件的文件名可以是一切合法的文件名;但如果一个Java源文件里定义了一个public修饰的类,则这个源文件的文件名必须与public修饰的类的类名相同。
14.不管上面哪种情况,当调用子类构造器来初始化子类对象时,父类构造器总会在子类构造器之前执行;不仅如此,执行父类构造器时,系统会再次上溯执行其父类构造器......依次类推,创建任何java对象,最先执行的总是java.lang.Object类的构造器。
16.当创建java对象时,系统总是先调用该类里定义的初始化块。初始化块虽然也是Java类的一种成员,但它没有名字,也就没有标识,因此无法通过类、对象来调用初始化块。初始化块只在创建java对象时隐式执行,而且在执行构造器之前。
18.与构造器类似,创建一个Java对象时,不仅会执行该类的普通初始化块和构造器,而且系统还会一直上溯到java.lang.Object类,先执行java.lang.Object类的初始化块,开始执行 java.lang.Object的构造器,依次向下执行其父类的初始化块,开始执行其父类的构造器.....最后才执行该类的初始化块和构造器,返回该类的对象。
19.初始化块定义时使用static修饰符,这个初始化块就变成了静态初始化块,也被称为类初始化块(普通初始化块负责对对象执行初始化,类初始化块负责对类进行初始化)。静态初始化块是类相关的,系统将在类初始化阶段执行静态初始化块,而不是在对象创建时执行。因此静态初始化块总是比普通初始化块先执行。
20.与普通初始化块类似的是,系统在类初始化阶段执行静态初始化块时,不仅会执行本类的静态初始化块,而且还会一直上溯到java.lang.Object类(如果他包含静态初始化块),先执行java.lang.Object类的静态初始化块(如果有),然后执行其父类的静态初始化块......最后才执行该类的静态初始化块。
22.java提供了final关键字来修饰变量、方法和类,系统不允许为final变量重新赋值,子类不允许覆盖父类的final方法,final类不能派生子类。通过使用final关键字,允许java实现不可变类,不可变类会让系统更安全。
Integer int1 = 2;
Integer int2 = 2;
System.out.println(int1 == int2);
Integer int3 = 128;
Integer int4 = 128;
System.out.println(int3 == int4);
结果是true,false。原因在于观察Integer源码可知内部会管理一个长度为256的Integer数组,里面存了-128-127所有整数,所以把一个-128-127之间的数自动装箱成一个Integer实例时,实际是指向cache数组中的一个元素,所以它们完全相等,而每次把不在-128-127之间的整数自动装箱,就会不相等。
24.对于直接做+运算的两个字符串(字面量)常量,并不会放入String常量池中,而是直接把运算后的结果放入常量池中;对于先声明的字符串字面量常量,会放入常量池,但是若使用字面量的引用进行运算就不会把运算后的结果放入常量池中了;总结一下就是JVM会对String常量的运算进行优化,未声明的,只放结果;已经声明的,只放声明
25.final修饰的成员变量必须由程序员显式的指定初始值,final修饰的类变量必须在静态初始化块中指定初始值或声明该类变量时指定初始值,而且只能在两个地方的其中之一指定;final修饰的实例变量必须在非静态初始化块、声明该实例变量或构造器中指定初始值,而且只能在三个地方的其中之一指定。
27.当时用final修饰基本类型变量时,不能对基本类型变量重新赋值,因此基本类型变量不能被改变。但对于引用类型变量,它保存的仅仅是一个引用,final只保证这个引用类型变量所引用的地址不会改变,即一直引用同一个对象,但是这个对象完全可以发生改变。
30.抽象类必须使用abstract修饰符来修饰,抽象方法也必须使用abstract修饰符来修饰,抽象方法不能有方法体;抽象类不能被实例化,无法使用new关键字来调用抽象类的构造器创建抽象类实例。即使抽象类里不包含抽象方法,这个抽象类也不能创建实例;抽象类可以包含成员变量、方法(普通方法和抽象方法都可以)、构造器、初始化块、内部类(接口、枚举)5种成分。抽象类的构造器不能用于创建实例,主要是用于被其子类调用;含有抽象方法的类(包括直接定义了一个抽象方法;或继承了一个抽象父类,但没有完全实现父类包含的抽象方法;或实现了一个接口,但没有完全实现接口包含的抽象方法三种情况)只能被定义成抽象类。
32.java8允许在接口中定义默认方法,默认方法必须使用default修饰,该方法不能使用static修饰,无论程序是否指定,默认方法总是使用public修饰如果开发者没有指定public,系统会自动为默认方法添加public修饰符。由于默认方法并没有static修饰,因此不能直接使用接口来调用默认方法,需要使用接口的实现类的实例来调用默认方法。
33.java8允许在接口中定义类方法,类方法必须使用static修饰,该方法不能使用default修饰,无论程序是否指定,类方法总是使用public修饰--如果开发者没有指定public,系统会自动为类方法添加public修饰符。类方法可以直接使用接口来调用。
38.Lambda表达式:形参列表。形参列表允许省略参数类型。如果形参列表只有一个参数,甚至连形参列表的圆括号也可以省略;箭头(->)。必须通过英文中画线号和大于符号组成;代码块。如果代码块只包含一条语句,Lambda表达式允许省略代码块的花括号,那么这条语句就不要用花括号表示语句结束。Lambda代码块只有一条return语句,甚至可以省略return关键字。Lambda表达式需要返回值,而它的代码块中仅有一条省略了return的语句,Lambda表达式会自动返回这条语句的值。
39.Lambda表达式的类型,也被称为“目标类型”,Lambda表达式的目标类型必须是“函数式接口”。函数式接口代表只含有一个抽象方法的接口。函数式接口可以包含多个默认方法、类方法,但只能声明一个抽象方法。
41.为了保证Lambda表达式的目标类型是一个明确的函数式接口,一般有如下三种常见形式:将Lambda表达式赋值给函数式接口类型的变量;将Lambda表达式作为函数式接口类型的参数传给某个方法;使用函数式接口对Lambda表达式进行强制类型转换。
43.引用类方法:示例(类名::类方法),说明(函数式接口中被实现方法的全部参数传给该类方法作为参数),对应的Lambda表达式:(a,b,c...)->类名.类方法(a,b,c...);引用特定对象的实例方法:示例(特定对象::实例方法),说明(函数式接口中被实现方法的全部参数传给该方法作为参数),对应的Lambda表达式:(a,b,c...)->特定对象.实例方法(a,b,c...);引用某类对象的实例方法:示例(类名::实例方法),说明(函数式接口中被实现方法的第一个参数作为调用者,后面的参数全部传给该方法作为参数),对应的Lambda表达式:(a,b,c...)->a.实例方法(b,c...);引用构造器:示例(类名::new),说明(函数式接口中被实现方法的全部参数传给该构造器作为参数),对应的Lambda表达式:(a,b....)->new 类名(a,b,...);
@FunctionalInterface
public interface Converter {
Integer converter(String from);
}
Converter converter=from->Integer.valueOf(from); 改写之后:Converter converter=Integer::valueOf;
Integer val1=converter.converter("99");
System.out.println(val1);
Converter converter2 = from -> "fkit.org".indexOf(from); 改写之后:Converter converter2="fkit.org"::indexOf;
@FunctionalInterface
public interface MyTest {
String test(String a, int b, int c);
}
MyTest myTest = (a, b, c) -> a.substring(b, c); 改写之后:MyTest myTest = String::substring;
@FunctionalInterface
public interface YourTest {
JFrame win(String title);
}
YourTest yourTest = a -> new JFrame(a); 改写之后:YourTest yourTest = JFrame::new;
44.Lambda表达式和匿名内部类的相同点:Lambda表达式与匿名内部类一样,都可以直接访问“effectively final”的局部变量,以及外部类的成员变量(包括实例变量和类变量);Lambda表达式创建的对象与匿名内部类生成的对象一样,都可以直接调用从接口中继承的默认方法。
45.Lambda表达式和匿名内部类的不同点:匿名内部类可以为任意接口创建实例--不管接口包含多少个抽象方法,只要匿名内部类实现所有的抽象方法即可,但Lambda表达式只能为函数式接口创建实例;;匿名内部类可以为抽象类甚至普通类创建实例,但Lambda表达式只能为函数式接口创建实例;匿名内部类实现的抽象方法的方法体允许调用接口中定义的默认方法;但Lambda表达式的代码块不允许调用接口中定义的默认方法。
46.枚举类和普通类的区别:枚举类可以实现一个或多个接口,使用enum定义的枚举类默认继承了java.lang.Enum类,而不是默认继承Object类,因此枚举类不能显式继承其他父类。其中java.lang.Enum类实现了java.lang.Serializable和java.lang.Comparable接口;使用enum定义、非抽象的枚举类默认会使用final修饰,因此枚举类不能派生子类;枚举类的构造器只能使用private访问控制符,如果省略了构造器的访问控制符,则默认使用private修饰,如果强制指定访问控制符,则只能指定private修饰符;枚举类的所有实例必须在枚举类的第一行显式列出,否则这个枚举类永远都不能产生实例,列出这些实例时,系统会自动添加public static final修饰,无需程序员显式添加。
48.java垃圾回收机制的特性:垃圾回收机制只负责回收堆内存中的对象,不会回收任何物力资源(例如数据库连接、网络IO等资源);程序无法精确控制垃圾回收的运行,垃圾回收会在合适的时候进行。当对象永久的失去引用后,系统就会在合适的时候回收它所占的内存;在垃圾回收机制回收任何对象之前,总会先调用它的finalize()方法,该方法可能使该对象重新复活(让一个引用变量重新引用该对象),从而导致垃圾回收机制取消回收。
49.大部分时候,程序强制系统垃圾回收后总会有一些效果。强制系统垃圾回收有如下两种方式:调用System类的gc()静态方法:System.gc();调用Runtime对象的gc()实例方法:Runtime.getRuntime().gc()。
50.对象的引用:强引用(StrongReference,程序创建一个对象,并把这个对象赋给一个引用变量,程序通过该引用变量来操作实际的对象);软引用(SoftReference,需要通过SoftReference类来实现,当一个对象只有软引用时,它有可能被垃圾回收机制回收。对于只有软引用的对象而言,当系统内存空间足够时,他不会被系统回收,程序也可使用该对象,当系统内存不足时,系统可能会回收它。软引用通常用于堆内存敏感的程序中);弱引用(WeakReference,通过WeakReference类实现,弱引用和软引用类似,但是引用级别更低。对于只有弱引用的对象而言,当系统垃圾回收机制运行时,不管系统内存是否足够,总会回收该对象所占用的内存。当然,并不是说当一个对象又有弱引用时,它就会立即被回收--正如那些失去引用的对象一样,必须等到系统垃圾回收机制运行时才会被回收);虚引用(PhantomReference:通过PhantomReference类实现,虚引用完全类似于没有引用。虚引用对对象本身没有太大影响,对象甚至感觉不到虚引用的存在。如果一个对象只有一个虚引用时,那么它也没有引用效果大致相同。虚引用主要用于跟踪对象被垃圾回收的状态,虚引用不能单独使用,虚引用必须和引用队列(ReferenceQueue)联合使用)。
51.使用这些引用类可以避免在程序执行期间将对象留在内存中。如果以软引用、弱引用或者虚引用的方式引用对象,垃圾回收器就能够随意地释放对象。如果希望尽可能减小程序在其生命周期中所占用的内存大小时,这些引用类就很有用处。
obj = wr.get();
if(obj == null){
wr = new WearReference(recreateIt());
obj = wr.get();
}
//使用obj...
obj = null;
obj = wr.get();
if(obj == null){
obj = recreateIt();
wr = new WearReference(obj);
}
//使用obj...
obj = null;
54.System类提供了一个identityHashCode(Object x)方法,该方法返回指定对象的精确hashCode值,也就是根据该对象的地址计算得到的hashCode值。当某个对象的hashCode方法被重写后,该类实例的hashCode()方法就不能唯一的标识该对象;但是通过identityHashCode()方法返回的hashCode值,依然是根据该对象的地址计算得到的hashCode值。所以如果两个对象的identityHashCode值相同,则两个对象绝对是同一个对象。
Runtime runtime=Runtime.getRuntime();
try {
runtime.exec("notepad.exe");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}