第6章面向对象(下)

6.1 java 1.8 增强的包装类

java 为什么要引入包装类

1. java 是面向对象的编程语言,但它也包含了8中基本数据类型,这8中基本数据类型不支持面向对象的编程机制,基本数据类型的数据也不具备“对象”的特征 :没有成员变量,没有方法可以调用  

2.只能进行简单的,有效的常规数据处理,当所有引用都继承了Object类,都可以当Object类使用,基本数据类型就不可以

 

自动装箱 :就是可以吧一个基本类型的变量直接赋值给对应的包装类变量,或者赋值给Object变量(向上自动转型)

自动拆箱 :就是可以把包装类对象直接赋值给一个对应的基本类型

 

包装类还可以实现基本类型变量和字符串之间的转换,把字符串类型转化为基本类型的值有两种方法

1. 利用包装类提供的pareXxxString s)静态方法  (除了 Character

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

 

String 类提供valueOf()了将字符串转换为字符串

系统把 -128 ~127之间的整数自动装箱成Integer实例,因此在这个之间的自动装箱成了Integer实例 直接引用cache数组里的元素

 

java 1.7为所有的包装类都提供了一个静态的comparexxx val1 xxx val2) 来比较两个类型之间值的大小 Boolean 类型 true > false

无符号位最大的特点就是最高位不在当做符号位

 

6.2 处理对象

.toString()  类名 + @ + hashCode

 

6.2.2 == equals()

java程序中测试两个变量是否相等有两种方法 ==运算符 和equals()

== 判断相等

1.如果两个变量的基本类型相同 且都是数值类型的 只要两个变量值相等就为true

2.对于引用类型 只有他们指向同一个类型

 

常量池 包括 类 方法 接口中产生的常量 还包括字符串常量  存在栈内存里

 

equals()方法

1.equals() 本身是object类的一个实例方法  因此所有的引用变量都可以调用该方法来判断变量是否相等 但是本质和 == 没有区别

2.String重写的equals()方法 用来判断两个字符串是否相等

 

6.3 类成员

同一个类的所有类变量共享都一块内存空间

 

静态初始化块 在类的初始化阶段,系统会调用给类的静态初始化块来对类进行初始化,一旦类初始化完毕之后静态初始化块将永远得不到执行的机会

 

类变量不能访问实例变量的原因是 因为类变量的作用范围更大,可能出现类成员已经初始化完毕了 实例变量都还不曾初始化,从而导致错误

 

6.3.2 单例类(Singleton

1.构造器使用private修饰

2.必须提供一个static方法来访问

3.使用一个static修饰的成员变量来保存曾经创建的对象

 

6.4 final 修饰符

final 可以修饰类 变量 方法

修饰变量时 表示该变量一旦获得初始值就不可以被改变,final 既可以修饰成员变量(类变量可以在定义时就指定默认值 也可以通过 静态块初始化 中指定;实例变量 以在定义时就指定默认值也可以通过 块初始化和 构造器 中指定)也可以局部变量和形参

final修饰的成员变量必须由程序员显示指定初始值 程序不会为final成员进行初始化

 

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

final 修饰基本变量时 不能被重新赋值, 但是final 修饰引用变量时,只保证这个引用变量所引用的的地址不会发生变化,(不可以对引用变量重新赋值,但是可以改变引用对所指向象的内容)

 

6.4.4  可执行 宏替代 的final 变量

无论是 类变量 实例变量 还是局部变量 只要满足

1. 使用final修饰

2. 在定义时就指定了 final 变量的初始值

3. 该初始值在编译时就别确定下来

就可以相当一个直接量(编译器会把程序中用到这个变量的地方都替换成变量的值)

关于宏变量 对于实例变量来说 只有在定义变量时指定初始值才会 有宏变量

6.4.5 final 方法

final 修饰方法表示方法不能被重写 (Object类里有一个 getClass()

6.4.6 final

final 修饰类表示该类没有子类 (java.lang.Math

6.4.7 不可变类

不可变类的意思就是 创建该类的实例后,该实例变量时不可以改变的(java8个包装类和String类都是不可变的)

创建不可变类的原则

1. 使用private final 修饰该类的成员变量

2. 提供带参数的构造器,根据传入的参数来初始化该类里的成员变量

3. 仅为该类成员变量提供get方法 不能提供set方法

4. 有必要重写 Object 类的 hashCode() 和equals()方法

 

不可变类的实例在整个生命周期都处于 初始化状态

 

创建不可变类时应该注意

当创建不可变类时,如果它包含成员变量的类型是可变的,那么其对象的成员变量就依然是可以改变的 那么该不可变类依然是失败的  所有要特别注意引用成员变量

6.4.8 缓存实例的不可变量

不可变类的用途

不可变类的实例状态不可改变,可以很方便的被多个对象所共享,如果程序经常需要使用相同的不可变类,则应该缓存这种不可变类的实例 (缓存)

 

Integer类 就采用了缓存机制,如果程序执行 new构造器来创建Integer对象,则每次都是全新的对象, 如果采用 valueOf()方法在(-128 - 127)之间则采用缓存机制

 

6.5 抽象类

抽象类不能被实例化,抽象类的构造器主要是用于子类调用

 

abstract 不能修饰成员变量 局部变量和构造器

 

static 不能和abstract一起修饰方法,static abstract 可以一起修饰内部类

 

abstract修饰的方法不能用private修饰

 

 

6.6接口

java 1.8 提供了默认方法,默认方法可以提供实现方法

 

接口不能继承类,不能有构造器和初始化块

 

接口里可以包含 静态常量 方法(抽象方法 类方法 或者默认方法  ) 内部类(包括内部接口 枚举)且 都是 public 访问权限

 

对于接口里的静态常量而言 不管是否使用了public static final 修饰都是使用 public staticfinal来修饰

默认方法需要加public default 来修饰 类方法需要加 static修饰

 

因为默认方法不能使用static修饰 所有只能在实现类中的实例来调用

 

接口类似于总纲,它制定了整个系统的总纲,它制定各模板应该遵循的标准,因此接口不应该经常改动

抽象类 类似于 中间产品 这个中间产品已经实现了系统的部分功能,但这个产品并不完整 需要进一步的完善

 

6.6.6 面向接口编程

1.简单工厂模式:解耦合 假如某一个类需要组合另一个类 直接组合该类 或者组合一个工厂类

(1)创建一个接口(Output

(2)将这个接口做为属性传入实现类中(private Output out

(3)提供一个工厂类来创建接口的对象(return new Printer())

(4)写一个类来实现接口 (BetterPrint

(5)如果需要改变 可以将3的对象改成实现4的对象 就可以完成组合功能升级

 

2.命令模式 :某一个方法需要完成某一个行为,这个行为的具体实现无法确定,必须等到执行该方法时才可以确定,所以必须传入一个 处理行为做参数来实现

(1)创建一个接口 定义一个处理行文的方法 (Command

(2)创建一个处理类  该类无法处理具体行为(public void processint[] target Command cmd ))

(3)具体实现类 类中方法的参数改为实现接口的不同类

pa.process(target , new PrintCommand());

pa.process(target, newAddCommand();

 

6.7内部类

内部类的作用

1.内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许包中的其他类访问

2.内部类可以访问外部类的私有成员

3.匿名内部类适合用于创建仅需要使用一次的类

 

内部类和外部类的区别

1.内部类比外部类可以多使用3个修饰符 private protect static

2.非静态内部类不能用于静态成员

 

 

6.7.1 非静态内部类

大部分时候内部类都是定义为成员内部类定义 (局部内部类是在方法中定义的类)

 

在外部类使用非静态内部类和平时普通类并没有太大区别

 

非静态类可以直接访问外部类private成员

因为在非静态内部类对象里,保存了一个外部类对象的引用

 

当外部类 内部类 内部类的局部变量重名是 可以使用 外部类名.this this 来做区分

 

非静态内部类的成员可以直接访问外部类的私有成员 反之则不成立 非静态内部类的成员只是在非静态内部类范围内可知的,如果外部类需要访问非静态类的内部类成员, 则必须显示创建非静态内部类的对象来调用访问其实例变量

 

如果存在一个非静态内部类对象时,则一定存在一个被他寄存的外部类对象,反之 则不一定成立 所以 外部类对象不能直接访问非静态内部类对象

 

非静态内部类里不能有 静态方法 静态成员 静态初始化块

 

6.7.2 静态内部类

静态内部类可以包含静态成员,也可以包含非静态成员 静态内部类成员不能访问外部类的实例成员 即使是静态内部类的实例方法也不能访问外部类的实例成员,只能访问外部类的静态成员

 

静态内部类是外部类的一个静态成员,因此外部类的所有成员都可以使用静态内部类来定义变量,创建对象;

外部类依然不能直接访问静态内部类的成员,但可以通过静态内部类作为调用者来访问静态内部类的类成员,也可以使用静态内部类对象作为调用者来访问静态内部类成员

 

接口也可以定义内部类 但只能是静态内部类

 

6.7.3 使用内部类

定义类的主要作用就是用来 定义变量 创建实例 和作为父类被继承,定义内部类的作用也主要是这样 但是内部类定义和创建实例和外部类有一定的差距

1. 在外部类内部使用内部类

区别 不要在外部类的静态成员使用非静态内部类

2. 在外部类之外使用非静态内部类

(1)不能使用private 修饰内部类

外部类.内部类 varName(如果外部类有包名,则加上包名)

(2)创建非静态内部类对象时,必须先创建外部类对象

(3)在创建非静态内部类的子类时,必须保证让子类构造器可以调用非静态内部类的构造器,调用非静态内部类的构造器时,必须存在一个外部类对象

public class SubClass extends Out.In {

public SubClass(Out out) {

out.super();

因为内部类的构造器 必须使用外部类对象来掉

 

3 在外部类之外使用静态内部类

new外部类.内部类构造器()

 

6.7.4局部内部类

如果把一个内部类定义在方法里,那么这个内部类就是局部内部类,局部内部类仅在该方法体力有效,所以不能使用访问控制符static修饰符修饰

 

6.7.5 java 8 改进的匿名内部类

匿名内部类适合创建那种只需要使用一次的类,匿名内部类必须继承一个父类,或者实现一个接口

关于匿名内部类还有两个规则

1.匿名内部类不能是抽象类系统创建匿名内部类时,会立即创建匿名内部类的对象

2.匿名内部类不能定义构造器,因为匿名内部类没有类名,所有无法定义构造器,但可以有初始化块 所以new接口名后不能带参数, 但如果通过继承父类来创建匿名内部类,则将拥有和父类相似的构造器 则拥有相同的形参列表

 

java 8之前

要求被局部内部类,匿名内部类访问的局部变量必须使用final 修饰,但是成员变量的值依然不可以改变

6.8  Lambda表达式

Lambda 表达式支持将代码块作为方法参数

 

Lambda 语言结构

 

1.形参列表 形参列表允许省略形参类型,如果参数列表只有一个参数,甚至可以连参数列表的圆括号也省略

2.箭头->

3.代码块

如果代码块只有一句语句,Lambda可以省略代码块的花括号,

如果lambda 语句只有一条return 语句,甚至可以省略 return

6.8.2 lambda 表达式与函数接口

Lambda表达式类型,也别称为 目标类型, Lambda表达式的目标类型必须是 函数式接口(函数式接口代表只包含一个抽象方法的接口,但是可以包含类方法 和默认方法)

 

Lambda表达式的结果就是被当成对象,因此程序中完全可以使用Lambda表达式进行赋值

 

Lambda 表达式有两个局限

1.lambda表达式的目标类型必须是函数式接口

2.lambda 表达式只能为函数式接口创建对象, 因此只能实现一个方法,

 

为了保证lambda表达式的目标类型必须是明确的函数式接口 有以下3中常见的方式

1. 将lambda 表示式赋值给函数式接口类型变量

2. 将lambda 表达式作为函数接口类型的参数传给某一个方法

3. 使用函数式接口对lambda表达式进行强制类型转换

 

6.8.3 方法引用与构造器引用

如果lambda表达式只有一条代码,还可以在代码块中使用 方法引用和构造器

需要使用2个英文冒号

 

方法引用和构造器引用可以让Lambda表达式代码更加简洁

引用类方法 类名::类方法 (a,b,...->类名.方法名(a,b,...)

引用特定对象的实例 特定对象::实例方法 (a,b,...)->特定对象.实例方法(a,b,...

引用某类对象的实例方法  类名::实例方法 (a,b,...)-> a.实例方法(b,...)

引用构造器  类名::new   (a,b,...) ->new 类名(a,b,...a

 

6.8.4 Lambda表达式和匿名内部类的联系和区别

相同点

Lambda 表达式与内部类一样 都可以直接访问 effectively final 的局部变量 以及外部类的成员变量

Lambda表达式创建对象和匿名类创建对象一样 都可以直接调用从接口中继承的默认方法

 

区别

1. 匿名内部类可以为任意接口创建实例

2. 匿名内部类可以为抽象类甚至是普通类创建实例

3. 匿名内部类实现的抽象方法的方法体允许调用接口中定义的默认方法,lambda表达式不允许调用默认方法

 

6.9 枚举类

在某些情况下一个类的对象固定而且有限,在java里被称为枚举类

java5新增了一个enum 关键字用来定义枚举类

 

6.9.1枚举类入门

枚举类和普通类的区别

1.枚举类默认继承java.lang.Enum类,因此不能显示继承其他父类

2.使用enum定义、非抽象枚举默认都会使用final修饰 因此不能有子类

3.枚举类的构造器只能使用private访问修饰符

4.枚举类的实例都必须在枚举类的第一行显示列出

 

枚举类提供了一个values()方法可以遍历出所有的枚举值

 

6.9.3枚举类的成员变量、方法和构造器

当创建MALE这样的枚举值并不是直接创建枚举类的实例 而是相当于创建了枚举类的匿名子类的实例

 

抽象枚举类使用的是abstract 而并非final

 

6.10 对象与垃圾回收机制

垃圾回收机制的特点

1.垃圾回收机制只能回收堆内存的对象,不会回收任何物理资源

2.程序无法精确的控制垃圾回收机制的运行,只会在合适的时候进行

3.在垃圾回收机制回收任何对象之前,总会先调用它的finalize()方法,该方法有可能使该对象重新复活

 

6.10.1 对象在内存中的状态

根据引用的状态 可分为三个状态 可达状态(有引用变量引用它) 可恢复状态(不在有引用指向) 不可达状态(引用被切断 却调用了finalize()方法 认没有达到可达状态)

 

当某一个对象被其他类变量引用,只有该类被销毁后,该对象才可以变成可恢复状态

当某一个对象被其他对象的实例变量引用 只有当该对象被销毁后,才会变成可恢复状态

 

6.10.2 强制垃圾回收

垃圾回收时间总是不确定的 但是程序强制系统垃圾回收总是有些效果的

System.gc();

Runtime.getRuntime().gc();

6.10.3 fianlize方法

finalize java提供的默认机制来清理该对象的资源,该方法是定义在Object类里的实例方法 当方法返回后,对象消失,垃圾回收机制执行

fianlize()方法4个特点

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

2. finalize()调用时间具有不确定性

3. 当jvm执行finalize()方法时,该对象可能会达到可达状态

4. 当jvm执行finalize()方法异常时,垃圾回收机制不会报告异常,而是继续执行

 

6.10.4 对象的软 弱和虚引用

1.强引用 java最常见的引用方式 ,程序创建一个对象,并把这个对象赋给一个引用变量,

程序通过这个引用变量来操作实际的对象(处于可达状态)

 

2.软引用 软引用通过SoftReference 类来实现 当一个类只有软引用时,它可能被GC回收 当系统内存不足时,系统可能就会回收它。(用于对内存敏感的程序中)

 

3.弱引用 通过WeakReference 类实现 当GC运行时,无论内存足不足都没被回收对象所占的内存

 

4.虚引用 通过实现PhantomReference 类实现,虚引用完全类似于没有引用,虚引用本身对对象没有太大影响  主要用于跟踪对象被垃圾回收的状态 虚引用不能单独存在,必须和引用队列一起存在

上面3个引用都包含了一个get()方法,用于获取被它们所引用的对象

 

引用队列 是用于保存被回收的对象的引用,使得对象在回收之前还可以采取行动

软引用和弱引用可以单独使用 ,但虚引用不能 主要用于跟踪对象被GC回收状态, 和检查引用队列是否包含 从而了解虚引用对象是否将被回收

 

 

6.11 修饰符的使用范围

strictfp 关键字的含义是 FP-strict(精确浮点) 用于外部类 接口 方法 和成员内部类

native 用来修饰方法  如果某一个方法需要利用平台相关特性,或者访问硬件等,就可以采用native 修饰的方法,再把该方法叫给C去实现  但是一旦使用了native 就失去了跨平台的功能

 

abstractfinal 不能同时使用

abstractstatic 不能同时修饰方法 可以同时修饰内部类

abstract private 不能同时修饰方法 可以同时修饰内部类

private final可以同时修饰方法 但是没有意义

 

6.12 使用jar文件

自带的 META-INF/MANIFEST.MF的清单文件

jar 优点

1.安全 能够对JAR文件进行数字签名

2.加快下载速度

3.压缩

4.包封装

5.可移植

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值