《疯狂java讲义》读书笔记(二):面向对象

《疯狂java讲义》读书笔记(二):面向对象

由于时间关系,书里面一些内容是我省略了的,比如说内部类和lambda表达式。

1.关于Java8增强的包装类

​ 基本数据类型有8种,但是这8种基本数据类型并不指出面向对象的编程机制。为了解决8种基本数据类型不能当成Object类型变量使用的问题,就提供了包装类的概念。除了int和char之外,其他基本数据类型对应的包装类都是将其首字母大写即可,int->Integer,char->Character。

​ 基本类型变量和包装类对象之间的转换在JDK1.5之后通过自动装箱和自动拆箱实现。自动装箱就是可以把一个基本类型变量赋给对应的包装类变量或者给Object变量,自动拆箱与之相反。

//直接把一个基本类型变量赋给Integer
Integer inObj=999;
//直接把一个Integer对象赋给int类型的变量
int it=inObj;

​ 此外,包装类还可以实现基本类型和字符串之间的转换。

//利用包装类提供的parseXxx(String s)静态方法【Character可没有这种方法】和包装类提供的Xxx(String s)构造器可以将字符串类型的值转换为基本类型的值。
//利用String类的重载valueOf()方法,可以将基本类型变量转换成字符串。

//例子
//把特定字符串转换为int变量
String intStr="123";
int it1=Integer.parseInt(intStr);
int it2=new Integer(intStr);
//把特定字符串转换为float变量
String floatStr="4.56";
float ft=new Float(floatStr);
//把一个float变量转换成String变量
String ftStr=String.valueOf(2.345f);

​ 学Java的时候,老师肯定也说过String intStr=5+"",也可以转成字符串。

【说明1】虽然包装类型的变量是引用数据类型,但是包装类的实例和数值类型的值可以进行比较,比较规则是直接取出包装类实例所包装的数值来进行比较的。

Integer a=new Integer(5);
//true
System.out.println("5的包装类实例是否大于4.0 "+(a>4.0));

【说明2】如果比较两个包装类的实例,那么实际上比较的引用是否指向同一个对象。

//false
System.out.println("比较2个包装类的实例是否相等:"+new Integer(1==new Integer(1));

【说明3】先看一个例子,之所以单独拿出来说,是因为在牛客网刷题的时候遇到了一个类似的题目。

Integer ina=2;
Integer inb=2;
System.out.println("两个2自动装箱后是否相等:"+(ina==inb));//true
Integer biga=128;
Integer bigb=128;
System.out.println("两个128自动装箱后是否相等:"+(biga==bigb));//false;

​ 可以自己在电脑上跑一下,情况确实是酱紫的。那么为啥第一个是true第二个就是false了呢,之前在刷题日记里面也简单的说了下,当时的记录比较浅显。来看一下java.lang.Integer的源码。

//定义一个长度为256的Integer数字
static final Integer[] cache=new Integer[-(-128)+127+1];
static//执行初始化,创建-128导127的Integer实例,并且放入cache数组
	for(int i=0;i<cache.length;i++)
    {
      	cache[i]=new Integer(i-128);
    }
}

​ 从上面代码可以看出来,系统把一个-128~127之间的证书自动装箱成Integer实例并且放入cache里缓存,实际上把-128 ~127之间的任意证书装箱成Integer实例的时候,永远都是引用cache数字的同一个数字元素,所以这也就解释了为啥2==2是true。但是如果不在-128 ~127范围里,那么每次就得自动创建实例,显然就是个false。

2.==和equals()方法

​ 这两个方式很常见了,但是怎么用可能还是有些不清楚。当使用==来判断两个变量是否相等的时候,如果两个变量是基本类型且都是数值类型(类型不一定严格相同,int类的65和float的65.0f其实也是true),只要相同,那么就是true。如果是引用类型变量,只有指向同一个对象的时候,才返回true。

​ equals方法是Object类提供的,判断两个对象相等的标准和使用==运算符没区别,也是得指向同一个对象才是true,但是String类重写了该方法,所以如果用equals方法判断字符串是否相等的时候,实际上只要字符串包含的字符序列相同就可。

​ PS:“hello”和new String(“hello”)是不一样的。Java程序直接使用字符串直接量时,JVM将会使用常量池管理,但如果new的话,JVM会先使用常量池管理“hello”直接量,在调用String类的构造器创建新的String对象,新创建的对象被保存在堆内存种,也就是说new的话,实际上产生了2个字符串对象。

3.final修饰符

3.1 final成员变量

​ final修饰的类变量和成员变量能指定初始值的地方如下:

​ □ 类变量:必须在静态初始化块中指定初始值或者是声明类变量的时候。

​ □ 实例变量:必须在非静态初始化块、声明该实例变量或者构造器中指定初始值。

3.2 final修饰基本类型变量和引用类型变量的区别

​ 修饰基本类型变量的时候,不能对基本类型变量重新赋值,因此也不能被改变。但是引用类型变量,保存的仅仅是一个引用,final只保证了这个引用类型变量所引用的地址不改变,即一直引用同一个对象,但这个对象完全可以改变。比如说用final修饰一个int类型的数组,该数字可以重新排序,我们也可以给元素赋值,这些都是合法的。

3.3 final方法

​ 不希望子类重写父类的某个方法就可以用final修饰。但是如果用final修饰一个private访问权限的方法,在子类里面完全可以定义一个相同方法名、相同形参列表、相同返回值类型的方法。

//父类
private final void test(){}
//子类
public void test(){}

4.抽象类

​ 抽象方法和抽象类必须用abstract修饰符定义,有抽象方法的类肯定是个抽象类,但是抽象类里可以没有抽象方法。

​ 一些规则:

  • 抽象类必须使用abstract修饰符修饰,抽象方法也是如此,抽象方法没有方法体!
  • 抽象类不能被实例化,无法使用new关键字来调用抽象类的构造器创建实例。即使抽象类里面没有抽象方法,这个抽象类也不能创建实例。
  • 抽象类可以包含成员变量、方法、构造器、初始化块、内部类(接口或者枚举类)。抽象类的构造器适用于被其子类调用的。
  • 含有抽象方法的类只能被定义为抽象类。【这个情况还挺多的,比如说继承了抽象父类,但是没有完全世界抽象方法,或者是实现接口,但没有完全实现接口的抽象方法等等】
  • final和abstract不能一起用,static和abstract不能同时修饰某个方法(但是可以同时修饰内部类),abstract和private不能同时修饰方法。

5.接口

​ 接口可以有多个父接口,但接口只能继承接口没法继承类。接口里可以有成员变量【只能是静态常量】、方法【抽象实例方法、类方法或者默认方法】、内部类。

​ 定义接口的成员变量时,不管使不使用public static final修饰符,接口里的成员变量总是使用这三个修饰符来修饰,而且接口里没有构造器和初始化块,因此接口里定义的成员变量只能在定义时指定默认值。

6.枚举类

​ 书上关于枚举类的介绍挺多也挺详细的,在这里不想作为笔记的重点来记录。日后有时间再详细写写吧。

​ 枚举类和普通类的区别:

  • 枚举类可以实现1个或多个接口,使用enum定义的枚举类默认继承了java.lang.Enum类,而不是默认继承Object类,因此枚举类不能显示继承其他父类。其中java.lang.Enum类实现了java.lang.Serializable和java.lang.Comparable接口。
  • 使用enum定义、非抽象的枚举类默认会使用final修饰,因此不能派生子类。
  • 枚举类的构造器只能使用private访问控制符。
  • 枚举类所有实例必须在第一行显式列出,否则这个枚举类就永不能产生实例。默认是public static final修饰。
  • 枚举类里面虽然可以定义抽象方法,但是不能用abstract将枚举类定义为抽象类,系统会自动添加。

7.对象与垃圾回收

​ 垃圾回收机制仅回收堆内存中的对象,不回收物理资源(数据库连接什么的);程序无法精确控制垃圾回收的运行,垃圾回收会在合适的时候进行,当对象永久的失去引用后,就会在合适的时候回收所占用的内存;在回收任何对象之前,总会先调用finalize()方法,该方法可能使该对象重新复活(让一个引用变量重新引用该对象),从而导致垃圾回收机制取消回收。

​ 书里面涉及到了三个词可恢复状态、可达状态、不可达状态,对象失去引用就是不可达状态,每个对象创建之后会立即进入可恢复状态,如果有一个及以上的引用变量引用它,则会变成可达状态。

​ 强制回收有两种方式:System.gc()Runtime.getRuntime().gc()。强制只是建议系统立即进行垃圾回收,但是系统也完全也有可能不进行垃圾回收。

发布了58 篇原创文章 · 获赞 5 · 访问量 6278

猜你喜欢

转载自blog.csdn.net/weixin_40992982/article/details/103959454
今日推荐