lsh-zr

1. 所谓自动装箱,就是可以把一个基本类型变量直接赋给对应的包装类变量,或者赋给Object变量(ObJect是所有类的父类,子类对象可以直接赋给父类变量);自动拆

箱则与之相反,允许直接把包装类对象直接赋给一个对应的基本类型变量。

2.字符串类型转换为基本类型:

  (1)利用包装类提供的parseXxx(String  s)静态方法(除character之外的所有包装类都提供了该方法)。

  (2)利用包装类提供的Xxx(String s)构造器。

3.将基本类型转化为字符串:

   (1)valueOf()方法。

   (2)和“”进行连接。

4. 因此-128~127之间的同个整数自动装箱成Integer实例时,水远都是引用cache数组的同个数组元索,所以它们全部相等:但每次把一个不在-128~127范围内的整数自动装箱成Integer实例时,系统总是重新创建一个Integer实例,所以出现程序中的运行结果。

5. 无符号整数最大的特点是最高位不再被当成符号位,因此无符号整数不支持负数,其最小值为0。

6.object类提供的toString()方法总是返回该对象的实现类的“类名+@+hashCode”值。

7. 当使用==来判断两个变量是否相等时,如果两个变量是基本类型变量,且都是数值类型(不一定要求数据类型严格相同),则只要两个变量的值相等,就将返回true。

8. 对于两个引用类型变量,只有它们指向同一个对象时,==判断才会返回true 。==不可用于比较类型上没有父子关系的两个对象(否则会出现编译错误)。

9. 当使用new String("hello")时,JVM会先使用常量池来管理”hello”直接量,再调用String类的构造器来创建一个新的String对象,新创建的String对象被保存在堆内存中。换句话说,new String("hello")一共产生了两个字符串对象。

10. 常量池(constant pool )专门用于管理在编译时被确定并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口中的常量,还包括字符串常量。

11. equals()方法是Object类提供的一个实例方法,因此所有引用变量都可调用该方法来判断是否与其他引用变量相等。但使用这个方法判断两个对象相等的标准与使用==运算符没有区别,同样要求两个引用变量指向同一个对象才会返回true。因此这个Object类提供的equals()方法没有太大的实际意义,如果希望采用自定义的相等标准,则可采用重写equals方法来实现。

12.String已经重写了Objec的equals()方法

13. //重写equals()方法,提供自定义的相等标准

public boolean equals (Object obj)

(

//如果两个对象为同一个对象

if(this==obj)

return true;

//只有当obj是Person对象

if(obj !=null&&obj .getClass()==Person .class)

{

Person personObj=(Person)obj;

//并且当前对象的idStr与obj对象的idStr相等时才可判断两个对象相等

if(this.getIdStr().equals(personObj .getIdStr()))

{

return  true;

}

}

return false;

}

14. 对于instanceof运算符而言,当前面对象是后面类的实例或其子类的实例时都将返回true ,所以重写equals()方法判断两个对象是否是同一个类的实例时使用instanceof是有问题的。比如有一个Teacher类型的变量t,如果判断t instanceof Person,这也将返回true,但对于重写equals()方法的要求而言,通常要求两个对象是同一个类的实例,因此使用instanceof运算符不太合适。改为使用t.getClass()=Person.class比较合适,这行代码用到了反射基础。

15.通常而言,正确的重写equals()方法时应该满足下列条件:

    (1)自反性(2)对称性(3)传递性(4)一致性(5)对任何不是null的x,x.equals(null)一定返回false。

16. 当通过对象来访问类变量时,系统会在底层转换为通过该类来访问类变量。

17. 当使用实例来访问类成员时,实际上依然是委托给该类来访问类成员,因此即使某个实例为null,它也可以访问它所属类的类成员,这表明null对象可以访问它所属类的类成员。

18. 对static关键字而言,有一条非常重要的规则:类成员(包括方法、初始化块、内部类和枚举类)不能访问实例成员(包括成员变量、方法、初始化块、内部类和枚举类)。因为类成员是属于类的,类成员的作用域比实例成员的作用域更大,完全可能出现类成员己经初始化完成,但实例成员还不曾初始化的情况,如果允许类成员访问实例成员将会引起大量错误。

19.一个类始终只能创建一个实例,则这个类被称为单例类。

20.final修饰的成员变量必须由程序员显示地指定初始值。

21. 归纳起来,final修饰的类变量、实例变量能指定初始值的地方如下:

(1)类变量:必须在静态初始化块中指定初始值或声明该类变量时指定初始值,而且只能在两个地 方的其中之一指定。

(2)实例变量:必须在非静态初始化块、声明该实例变量或构造器中指定初始值,而且只能在三个  地方的其中之一指定。

22. 如果普通初始化块已经为某个实例变量指定了初始值,则不能再在构造器中为该实例变量指定初始值;

23. 类变量不能在普通初始化块中指定初始值,因为类变量在类初始化阶段已经被初始化了,普通初始化块不能对其重新赋值。

24. 与普通成员变量不同的是,final成员变量(包括实例变量和类变量)必须由程序员显式初始化,系统不会对final成员进行隐式初始化。

25. public class FinalLocalVariableTest

{

public void test (final int a)

{

//不能对final修饰的形参赋值,下面语句非法

//a=5;

}

public static void main (String[]args)

{

//定义final局部变量时指定默认值,则str变量无法重新赋值

final String str="hello";

//下面赋值语句非法

//str="Java";

//定义final局部变量时没有指定默认值,则d变量可被赋值一次

final double d;

//第一次赋初始值,成功

d = 5.6;

//对final变量重复赋值,下面语句非法

//d=3.4;

}

}

26. 因为形参在调用该方法时,由系统根据传入的参来完成初始化,因此使用final修饰的形参不能被赋值。

27. 当使用final修饰基本类型变量时,不能对基本类型变量重新赋值,因此基本类型变量不能被改变。但对于引用类型变量而言,它保存的仅仅是一个引用,final只保证这个引用类型变量所引用的地址不会改变,即一直引用同一个对象,但这个对象完全可以发生改变。

28. 对一个final变量来说,不管它是类变量、实例变量,还是局部变量,只要该变量满足三个条件,这个final变量就不再是一个变量,而是相当于一个直接量。

    (1)使用final修饰符修饰。

    (2)在定义该final变量时指定了初始值。

    (3)该初始值可以在编译时就被确定下来。

29.  public  class  FinalReplaceTest

{

    public static void main (String[]args)

      {

          //下面定义了4个final“宏变量”

          final int a=5+2;

          final double b=1.2/3;

          final String str=”疯狂”+"Java";

          final String book=”疯狂Java讲义:”+”99.0;

          //下面的book2变量的值因为调用了方法,所以无法在编译时被确定下来

          final String book2=”疯狂Java讲义:”+String.valueOf(99.0);//①

          System.out.println(book=="疯狂Java讲义:99.0");//输出true

          System.out.println(book2=="疯狂Java讲义:99.0");//输出false

      }

}

30. public class Str工ngJoinTest

{

    public static void main(String[] args)

    {

        String s1=”疯狂Java",

        //s2变量引用的字符串可以在编译时就确定下来

        //因此s2直接引用常量池中己有的”疯狂Java”字符串

        String s2=”疯狂”+"Java";

        System.out.println(sl==s2);

        //定义2个字符串直接量

        String strl=”疯狂”;//①

        String str2=”Java";//②

        //将str1和str2进行连接运算

        String s3=strl+str2;

        System.out.println(sl==s3);//输出false

    }

}

注:对于s3而言,它的值由str1和str2进行连接运算后得到。由于strl , str2只是两个普通变量,编译器不会执行“宏替换”,因此编译器无法在编译时确定s3的值,也就无法让s3指向字符串池中缓存的“疯狂Java "。由此可见,s1==s3将输出false。

31.对于final实例变量而言,只有在定义该变量时指定初始值才会有“宏变量”的效果。

32.final修饰的方法只是不能被重写,完全可以被重载。

33.final修饰的类不可以有子类。

34. 不可变(immutable)类的意思是创建该类的实例后,该实例的实例变量是不可改变的。Java提供的8个包装类和java.lang. String类都是不可变类,当创建它们的实例后,其实例的实例变量不可改变。

35. 如果需要创建自定义的不可变类,可遵守如下规则:

(1)使用private和final修饰符来修饰该类的成员变量。

(2)提供带参数构造器,用于根据传入参数来初始化类里的成员变量。

(3)仅为该类的成员变量提供getter方法,不要为该类的成员变量提供setter方法,因为普通方法无 法修改final修饰的成员变量。

(4)如果有必要,重写Object类的hashCode()和equals()方法。equals方法根据关键成员变量来作  为两个对象是否相等的标准,除此之外,还应该保证两个用equals()方法判断为相等的对象的 hashCode()也相等。

36.抽象方法是只有方法签名没有方法实现的方法。

37. 抽象方法和抽象类的规则如下。

(1)抽象类必须使用abstract修饰符来修饰,抽象方法也必须使用abstract修饰符来修饰,抽象方法  不能有方法体。

(2)抽象类不能被实例化,无法使用new关键字来调用抽象类的构造器创建抽象类的实例。即使抽  象类里不包含抽象方法,这个抽象类也不能创建实例。

(3)抽象类可以包含成员变量、方法(普通方法和抽象方法都可以)、构造器、初始化块、内部类(接  口、枚举)5种成分。抽象类的构造器不能用于创建实例,主要是用于被其子类调用。

(4)含有抽象方法的类(包括直接定义了一个抽象方法;或继承了一个抽象父类,但没有完全实现  父类包含的抽象方法;或实现了一个接口,但没有完全实现接口包含的抽象方法三种情况)只  能被定义成抽象类。

38. 当使用abstract修饰类时,表明这个类只能被继承;当使用abstract修饰方法时,表明这个方法必须由子类提供实现(即重写)。而final修饰的类不能被继承,final修饰的方法不能被重写。因此final和abstract永远不能同时使用。

39. abstract不能用于修饰成员变量,不能用于修饰局部变量,即没有抽象变量、没有抽象成员变量等说法;abstract也不能用于修饰构造器,没有抽象构造器,抽象类里定义的构造器只能是普通构造器。

40. 当使用static修饰一个方法时,表明这个方法属于该类本身,即通过类就可调用该方法,但如果该方法被定义成抽象方法,则将导致通过该类来调用该方法时出现错误(调用了一个没有方法体的方法肯定会引起错误)。因此static和abstract不能同时修饰某个方法,即没有所谓的类抽象方法。

41. static和abstract并不是绝对互斥的,static和abstract虽然不能同时修饰某个方法,但它们可以同时修饰内部类。

42. abstract关健字修饰的方法必须被其子类重写才有意义,否则这个方法将永远不会有方法体,因此abstract方法不能定义为private访问权限,即private和abstract不能同时修饰方法。

43. 接口和抽象类在用法上也存在如下差别:

(1)接口里只能包含抽象方法和默认方法,不能为普通方法提供方法实现;抽象类则完全可以包含    普通方法。

(2)接口里不能定义静态方法;抽象类里可以定义静态方法。

(3)接口里只能定义静态常量,不能定义普通成员变量;抽象类里则既可以定义普通成员变量,也  可以定义静态常量。

(4)接口里不包含构造器;抽象类里可以包含构造器,抽象类里的构造器并不是用于创建对象,而  是让其子类调用这些构造器来完成属于抽象类的初始化操作。

(5)接口里不能包含初始化块;但抽象类则完全可以包含初始化块。

(6)一个类最多只能有一个直接父类,包括抽象类:但一个类可以直接实现多个接口,通过实现多  个接口可以弥补Java单继承的不足。

44. 大部分时候,类被定义成一个独立的程序单元。在某些情况下,也会把一个类放在另一个类的内部定义,这个定义在其他类内部的类就被称为内部类(有的地方也叫嵌套类),包含内部类的类也被称为外部类(有的地方也叫宿主类)。

45. Java从JDK 1.1开始引入内部类,内部类主要有如下作用:

     (1)内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问 该类。假设需要创建Cow类,Cow类需要组合一个CowLeg对象,CowLeg类只有在Cow类里 才有效,离开了Cow类之后没有任何意义。在这种情况下,就可把CowLeg定义成Cow的内 部类,不允许其他类访问CowLeg 。

(2)内部类成员可以直接访问外部类的私有数据,因为内部类被当成其外部类成员,同一个类的成 员之间可以互相访问。但外部类不能访问内部类的实现细节,例如内部类的成员变量。

(3)匿名内部类适合用于创建那些仅需要一次使用的类。

46. (1)内部类比外部类可以多使用三个修饰符:private, protected, static—---外部类

      不可以使用这三个 修饰符。

      (2)非静态内部类不能拥有静态成员。

47.方法里定义的内部类被称为局部内部类。

48. 大部分时候,内部类都被作为成员内部类定义,而不是作为局部内部类。成员内部     类是一种与成员变量、方法、构造器和初始化块相似的类成员;局部内部类和匿名内部类则不是类成员。

49.成员内部类分两种:(1)静态内部类(2)非静态内部类

50. 成员内部类(包括静态内部类、非静态内部类)的class文件总是这种形式:OuterClass$InnerClass.class

51. 在非静态内部类对象里,保存了一个它所寄生的外部类对象的引用(当调用非静态内部类的实例方法时,必须有一个非静态内部类实例,非静态内部类实例必须寄生在外部类实例里)。

52. 当在非静态内部类的方法内访问某个变量时,系统优先在该方法内查找是否存在该名字的局部变量,如果存在就使用该变量;如果不存在,则到该方法所在的内部类中查找是否存在该名字的成员变量,如果存在则使用该成员变量;如果不存在,则到该内部类所在的外部类中查找是否存在该名字的成员变量,如果存在则使用该成员变量;如果依然不存在,系统将出现编译错误:提示找不到该变量。

53. 因此,如果外部类成员变量、内部类成员变量与内部类里方法的局部变量同名,则可通过使用this,外部类类名.this作为限定来区分。

54.不允许在外部类的静态成员中直接使用非静态内部类。

55.java不允许在非静态内部类里定义静态成员。

56. static关健字的作用是把类的成员变成类相关,而不是实例相关,即static修饰的成员属干整个类,而不属于单个对象。外部类的上一级程序单元是包,所以不可使用static修饰; 使用static修饰可以将内部类变成外部类相关,而不是外部类实例相关。因此static关键字不可修饰外部类,但可修饰内部类。

57.静态内部类可以包含静态成员,也可以包含非静态成员。

58.静态内部类的实例方法不能访问外部类的实例属性。(因为找不到被寄生的外部类对象,只能找到被寄生的外部类)

59. java还允许在接口里定义内部类,接口里定义的内部类默认使用public static修饰,也就足说,接口内部类只能是静态内部类。

60.在接口里面可以定义内部接口,但是没有意义。

61.(1)省略访问控制符的内部类,只能被与外部类处于同一个包中的其他类所访问。

(2)使用protected修饰的内部类,可被与外部类处于同一个包中的其他类和外部类的子类所访问。

(3)使用public修饰的内部类,可以在任何地方被访问。

62.在外部类以外的地方创建非静态内部类实例语法如下:

     Out.In  in=new Out().new In();

63.非态内部类的构造器必须通过其外部类对象来调用:

  调用内部类构造器:out.super();

64. 非静态内部类的子类不一定是内部类,它可以是一个外部类。但非静态内部类的子类实例一样需要保留一个引用,该引用指向其父类所在外部类的对象。也就是说,如果有一个内部类子类的对象存在,则一定存在与之对应的外部类对象。

65.在外部类以外的地方创建静态内部类的实例:

     StaticOut.StaticIn  in=new StaticOut.StaticIn();

66.内部类是不可以被重写的(因为他们的命名还与外部类名有关,处于不同的命名空间,所以他们的名字是不可能相同的)。

67. 由于局部内部类不能在外部类的方法以外的地方使用,因此局部内部类也不能使用访问控制符和static修饰符修饰。

68. 如果需要用局部内部类定义变量、创建实例或派生子类,那么都只能在局部内部类所在的方法内进行。

69. 因为同一个类里不可能有两个同名的成员内部类,而同一个类里则可能有两个以上同名的局部内部类(处于不同方法中),所以Java为局部内部类的class文件名中增加了一个数字,用于区分。

70.创建匿名内部类时会立即创建一个该类的实例,这个类定义立即消失,匿名内部类不能重复使用。

71.匿名内部类必须继承一个父类,或实现一个接口,但最多只能继承一个父类,或实现一个接口。

72. 关于匿名内部类还有如下两条规则:

(1)匿名内部类不能是抽象类,因为系统在创建匿名内部类时,会立即创建匿名内部类的对象。因 此不允许将匿名内部类定义成抽象类。

(2)匿名内部类不能定义构造器。由于匿名内部类没有类名,所以无法定义构造器,但匿名内部类可以定义初始化块,可以通过实例初始化块来完成构造器需要完成的事情。

73.最常用的创建匿名内部类的方式是需要创建某个接口类型的对象。

74.实例有限而且固定的类,在java里被称为枚举类。

75. 早期也可采用通过定义类的方式来实现,可以采用如下设计方式:

(1)通过private将构造器隐藏起来。

(2)把这个类的所有可能实例都使用public static final修饰的类变量来保存。

(3)如果有必要,可以提供一些静态方法,允许其他程序根据特定参数来获取与之匹配的实例。

(4)使用枚举类可以使程序更加健壮,避免创建对象的随意性。

76. 枚举类与普通类有如下简单区别:

(1)枚举类可以实现一个或多个接口,使用enum定义的枚举类默认继承了java.lang. Enum类,而不是默认继承Object类,因此枚举类不能显式继承其他父类。其中java.lang.Enum类实现了  java.lang.Serializable 和 java.lang. Comparable两个接口。

(2)使用enum定义、非抽象的枚举类默认会使用final修饰,因此枚举类不能派生子类。

(3)枚举类的构造器只能使用private访问控制符,如果省略了构造器的访问控制符,则默认使用 private修饰;如果强制指定访问控制符,则只能指定private修饰符。

(4)枚举类的所有实例必须在枚举类的第一行显式列出,否则这个枚举类永远都不能产生实例。列 出这些实例时,系统会自动添加public static final修饰,无须程序员显式添加。

77.枚举类默认提供了一个values()方法,该方法可以很方便的遍历所有的枚举值。

78.定义枚举类时需要显示列出所有的枚举值,所有的枚举值之间以英文逗号隔开,枚举值列举结束后以英文分号作为结束,这些枚举值代表了该枚举类的所有可能的实例。

79.通过enum的valueOf()方法来获取指定枚举类的枚举值。

       例:Season  s=Enum.valueOf(Season.class,”fall”);

80.一旦为枚举类显示定义了带参数的构造器,列出枚举值时就必须对应地传入参数

例:MALE(“男”),FEMALE(“女”);

相当于如下代码:

Public static final Gender  MALE=new Gender(“男“);

Public static final Gender  MALE=new Gender(“女“);

其中Gender是枚举类。

81. 在枚举类中列出枚举值时,实际上就是调用构造器创建枚举类对象,只是这里无须使用new关键字,也无须显式调用构造器。前面列出枚举值时无须传入参数,甚至无须使用括号,仅仅是因为前面的枚举类包含无参数的构造器。

82. 并不是所有的枚举类都使用了final修饰!非抽象的枚举类才默认使用final修饰。对于一个抽象的枚举类而言—----只要它包含了抽象方法,它就是抽象枚举类,系统会默认使用abstract修饰,而不是使用final修饰。

83. 如果由枚举类来实现接口里的方法,则每个枚举值在调用该方法时都有相同的行为方式(因为方法体完全一样)。如果需要每个枚举值在调用该方法时呈现出不同的行为方式,则可以让每个枚举值分别来实现该方法,每个枚举值提供不同的实现方式,从而让不同的枚举值调用该方法时具有不同的行为方式。

public enum Gender implements GenderDesc

{

//此处的枚举值必须调用对应的构造器来创建

           MALE(”男”)

           //花括号部分实际上是一个类体部分

           {

                      public void info()

                      {

                            System.out.println(”这个枚举值代表男性”);

                      }

           },

           FEMALE(”女”)

           {

                      public void info()

                      {

                            System.out.println(”这个枚举值代表女性”);

                      }

           };

     }

84.也可以为枚举类定义一个抽象方法,这个抽象方法由不同的枚举值提供不同的实现。

85. 枚举类里定义抽象方法时不能使用abstract关键字将枚举类定义成抽象类(因为系统自动会为它添加abstract关键字),但因为枚举类需要显式创建枚举值,而不是作为父类,所以定义每个枚举值时必须为抽象方法提供实现,否则将出现编译错误。

86.(1)垃圾回收机制只负责回收堆内存中的对象,不会回收任何物理资源(例如数据库连接、网络IO  等资源)。

(2)程序无法精确控制垃圾回收的运行,垃圾回收会在合适的时候进行。当对象永久性地失去引用后,系统就会在合适的时候回收它所占的内存。

(3)在垃圾回收机制回收任何对象之前,总会先调用它的finalize()方法,该方法可能使该对象重新复活(让一个引用变量重新引用该对象),从而导致垃圾回收机制取消回收。

87. 当一个对象在堆内存中运行时,根据它被引用变量所引用的状态,可以把它所处的状态分成如下:

(1)可达状态:当一个对象被创建后,若有一个以上的引用变量引用它,则这个对象在程序中处于可达状态,程序可通过引用变量来调用该对象的实例变量和方法。

(2)可恢复状态:如果程序中某个对象不再有任何引用变量引用它,它就进入了可恢复状态。在这种状态下,系统的垃圾回收机制准备回收该对象所占用的内存,在回收该对象之前,系统会调用所有可恢复状态对象的finalize()方法进行资源清理。如果系统在调用finalize()方法时重新让 一个引用变量引用该对象,则这个对象会再次变为可达状态:否则该对象将进入不可达状态。

(3)不可达状态:当对象与所有引用变量的关联都被切断,且系统已经调用所有对象的finalize()方法后依然没有使该对象变成可达状态,那么这个对象将永久性地失去引用,最后变成不可达状态。只有当一个对象处于不可达状态时,系统才会真正回收该对象所占有的资源。

88. 一个对象可以被一个方法的局部变量引用,也可以被其他类的类变量引用,或被其他对象的实例变量引用。当某个对象被其他类的类变量引用时,只有该类被销毁后,该对象才会进入可恢复状态;当某个对象被其他对象的实例变量引用时,只有当该对象被销毁后,该对象才会进入可恢复状态。

89. 强制系统垃圾回收有如下两种方式:

     (1)调用System类的gc()静态方法:System.gc()。

     (2)调用Runtime对象的gc()实例方法:Runtime.getRuntime().gc()。

90. 强制垃圾回收只是建议系统立即进行垃圾回收,系统完全有可能并不立即进行垃圾回收,垃圾回收机制也不会对程序的建议完全置之不理:垃圾回收机制会在收到通知后,尽快进行垃圾回收。

91. 某个失去引用的对象只占用了少量内存,而且系统没有产生严重的内存需求,因此垃圾回收机制并没有试图回收该对象所占用的资源,所以该对象的finalize()方法也不会得到调用。

92. fiinalize()方法具有如下4个特点:

(1)永远不要主动调用某个对象的finalize()方法,该方法应交给垃圾回收机制调用。

(2)finalize()方法何时被调用,是否被调用具有不确定性,不要把finalize()方法当成一定会被执行的方法。

(3)当JVM执行可恢复对象的finalize()方法时,可能使该对象或系统中其他对象重新变成可达状态。

(4)当JVM执行finalize()方法时出现异常时,垃圾回收机制不会报告异常,程序继续执行。

93.对象的强、软、弱、虚引用。

 

分类:

技术点:

相关文章: