第三周总结
第一天~第四天:三大特性(封装、继承、多态) 三个修饰符(abstract、static、final)、接口
第五天~第六天: String类型的扩充、常用类
第一天
封装
什么是封装
概念:尽可能隐藏对象的内部实现细节,控制对象的修改以及访问的权限
访问修饰符:private(将属性修饰为私有,仅本类可见)
##### 过滤有效数据
外界访问 不可直接访问私有属性 仅可访问公共方法
get/set方法是外界访问对象私有属性的唯一通道,方法内部可对数据进行检测和过滤
继承
生活中的"继承"是施方的一种赠与,受方的一种获得
将一方所拥有的东西给予另一方
往往二者之间具有继承关系(直系、亲属)
继承
语法:class 子类 extents 父类{}//定义子类时,显示继承父类
应用:产生继承关系后,子类可以使用父类中的属性和方法,也可定义子类独有的属性和方法
好处:既提高代码的复用性,又提高代码的可扩展性
继承的特点
java为单继承,一个类只由一个直接父类,但可以多级继承,属性和方法逐级叠加
不可继承
-
构造方法:
类中的构造方法,只负责创建本类对象,不可继承
-
private修饰的属性和方法:
访问修饰符的一种,仅本类可见
-
父子类不在同一个包package中,default修饰的属性和方法:
访问修饰符的一种,仅同包可见
访问修饰符
本类 | 同包 | 非同包子类 | 其他 | |
---|---|---|---|---|
private | √ | × | × | × |
default | √ | √ | × | × |
protected | √ | √ | √ | × |
public | √ | √ | √ | √ |
方法的覆盖
当父类提供的方法无法满足子类需求时,可在子类中定义和父类相同的方法进行覆盖(Override)
方法重写的规则:
方法名必须相同
方法参数列表必须相同(个数、类型、顺序)
方法的返回值必须相同或返回值类型的子类
方法的访问修饰符,只能比父类更宽,不能更严
-
方法覆盖原则:
方法名称、参数列表、返回值类型必须与父类相同
访问修饰符可与父类相同或是比父类更宽泛
-
方法覆盖的执行:
子类覆盖父类方法后,调用时优先执行子类覆盖后的方法
super关键字
在子类中,可直接访问从父类继承到的属性和方法,但如果父子类的属性或方法存在重名(属性遮蔽、方法覆盖)时,需要加以区分,才可专项访问
super调用父类无参构造
super();表示调用父类无参构造方法,如果没有显示书写,隐式存在于子类构造方法的首行
super调用父类有参构造
super();表示调用父类无参构造方法
super(实参);表示调用父类有参构造方法
this与super
this或super使用在构造方法中时,都要求在首行
当子类构造中使用了this()或this(实参)
即不可再同时书写super()或super(实参)
会由this()指向的构造方法完成super()的调用
总结
-
super关键字的第一种用法
在子类的方法中使用"super."的形式访问父类的属性和方法
例如:super.父类属性或super.父类方法();
-
super关键字的第二种用法
在子类的构造方法的首行,使用"super()“或"super(实参)”,调用父类构造方法
-
注意
如果子类构造方法中,没有显示定义super()或super(实参),则默认提供super()
同一个子类构造方法中,super()、this()不可同时存在
多态
程序中的多态
概念:父类引用指向子类对象,从而产生多种形态
二者具有直接或间接的继承关系,父类引用可指向子类对象,即形成多态
父类引用仅可调用父类所声明的属性和方法,不可调用子类独有的属性和方法
多态中的方法覆盖
如果子类中覆盖了父类中的方法,以父类型引用调用此方法时,优先执行父类还是子类中的方法?
实际运行过程中,依旧遵循覆盖原则,如果子类覆盖了父类中的方法,则执行子类中覆盖后的方法,否则执行父类中的方法
多态的应用
-
场景一
使用父类作为方法形参实现多态,使方法参数的类型更为宽泛
-
场景二
使用父类作为方法返回值实现多态,使方法可以返回不同子类对象
向上转型(装箱)
父类引用中保存真实子类对象,称为向上转型(即多态核心概念)
注意:仅可调用Animal中所声明的属性和方法
向下转型(拆箱)
将父类引用中的真实子类对象强转回子类本身类型,称为向下转型
注意:只有转换回子类真实类型,才可调用子类独有的属性和方法
类型转换异常
java.lang.ClassCastException
向下转型时,如果父类引用的子类对象类型和目标类型不匹配,则会发生类型转换异常
instanceof关键字
向下转型前,应判断引用中的对象真实类型,保证类型转换的正确性
语法:引用类型 instanceof 类型//返回boolean类型结果
总结
多态的两种应用场景:
-
使用父类作为方法形参,实现多态
调用方法时,可传递的实参类型包括:本类型对象+其所有的子类对象
-
使用父类作为方法返回值,实现多态
调用方法后,可得到的结果类型包括:本类型对象+其所有的子类对象
多态的作用:
屏蔽子类间的差异
灵活、耦合度低
第二天~第三天
abstract
抽象类的作用
作用:
1、可被子类继承,提供共性属性和方法
2、可声明为引用,强制使用多态
经验:
抽象父类,可作为子类的组成部分,依附于子类对象存在,
由父类共性+子类独有组成完整的子类对象
抽象方法
被abstract修饰的方法,称为抽象方法,只有方法声明,没有方法实现({}的部分没有)。意为不完整的方法,必须包含在抽象类中
产生继承关系后,子类必须覆盖父类中所有的抽象方法,否则子类还是抽象类
总结
abstract修饰类:不能new对象,但可以声明引用
abstract修饰方法:只要方法声明,没有方法实现。(需包含在抽象类中)
抽象类中不一定有抽象方法,但有抽象方法的类一定是抽象类
子类继承抽象类后,必须覆盖父类所有的抽象方法,否则子类还是抽象类
static
实例属性
实例属性是每个对象各自持有的独立空间(多份),对象单方面修改,不会影响其他对象
静态属性
静态属性是整个类共同持有的共享空间(一份),任何对象修改,都会影响其他对象
什么是静态
概念:
- 静态(static)可以修饰属性和方法
- 称为静态属性(类属性)、静态方法(类方法)
- 静态成员是全类所有对象共享的成员
- 在全类中只有一份,不因创建多个对象而产生多份
- 不必创建对象,可直接通过类名访问
静态方法
已知静态方法:
- Arrays.copyOf();
- Arrays.sort();
- Math.random();
- Math.sqrt();
- 均使用类名直接调用
静态的特点
静态方法允许直接访问静态成员
静态方法不能直接访问非静态成员
静态方法中不允许使用this或是super关键字
静态方法可以继承,不能重写、没有多态
类加载
JVM首次使用某个类时,需通过CLASSPATH查找该类的.calss文件
类对象是一种数据类型 保存类的信息 类对象类的描述信息
将.class文件对类的描述信息加载到内存中,进行保存
如:包名、类名、父类、属性、方法、构造方法
加载时机:
- 创建对象
- 创建子类对象
- 访问静态属性
- 调用静态方法、
- Class.forName(“全限定名”);
静态代码块
类加载时,触发静态代码块的执行(仅一次)。执行地位:静态属性初始化之后。
作用:可为静态属性赋值,或必要的初始行为
注:方法只有被调用才会执行
初始化静态属性、读取配置文件
总结
- static修饰的成员为静态成员,无需创建对象,可直接通过类名访问
- 静态方法不能直接访问非静态方法
- 静态方法中不能使用this或是super
- 静态方法可以继承、不能重写、没有多态
- 静态代码块在类加载时被执行,但只执行一次
final
什么是最终
概念:最后的、不可更改的
final可修饰的内容:
- 类(最终类)
- 方法(最终方法)
- 变量(最终变量)
final类
final修饰类:此类不能被继承
String、Math、System均为final修饰的类、不能被继承
final修饰方法:此方法不能被覆盖
意为最终方法,不支持子类以覆盖的形式修改
final变量
final修饰变量:此变量值不能被改变(常量)
所有final修饰的变量只能赋值一次,值不允许改变
实例常量
实例常量不再提供默认值,必须手动赋予初始值。
赋值时机:显示初始化、动态代码块、构造方法
如果有多个构造方法,必须保证每个构造方法都会对常量进行赋值
注意:如果在构造方法中为实例常量赋值,必须保证所有构造方法都能对其正确赋值
静态常量
静态常量
静态常量不再提供默认值,必须手动赋予初始值。
赋值时机:显示初始化、静态代码块
对象常量
final修饰的基本类型:值不可变
final修饰的引用类型:地址不可变
总结
-
final修饰类:此类不能被继承
-
final修饰方法:此方法不能被覆盖
-
final修饰变量:此变量值不能被改变(无初始值、只允许赋值一次)
局部常量:显示初始化
实例常量:显示初始化、动态代码块、构造方法
静态常量:显示初始化、静态代码块
基本数据类型常量:值不可变
引用数据类型常量:地址不可变
第四天
接口
接口的语法
接口相当于特殊的抽象类,定义的方式、组成部分与抽象类类似
使用interface关键字定义接口
只能定义:公开静态常量、公开抽象方法
没有构造方法,不能创建对象
与抽象类的异同
相同:
- 可编译成字节码文件
- 不能创建对象
- 可作为引用类型
- 具备Object类中所定义的方法
不同:
- 所有属性都是公开静态常量,隐式使用public static final修饰
- 所有方法都是公开抽象方法,隐式使用public abstract修饰
- 没有构造方法、动态代码块、静态代码块
什么是接口
微观概念:接口是一种能力和约定
- 接口的定义:代表了某种能力
- 方法的定义:能力的具体要求
经验:Java为单继承,当父类的方法种类无法满足子类需求时,可实现接口扩充子类能力
接口支持多实现,可为类扩充多种能力
接口的规范
任何类在实现接口时,必须实现接口中所有的抽象方法,否则此类为抽象类
实现接口中的抽象方法时,访问修饰符必须是public
接口的引用
同父类一样,接口也可声明为引用,并指向实现类对象
注意:
仅可调用接口中所声明的方法,不可调用实现类中独有的方法
可强转回实现类本身类型,进行独有方法调用
接口的多态
多种不同类型的引用指向同一个对象时,表示看待对象的视角不同
不同引用所能看到的对象范围不同,只能调用自身类型中所声明的部分
不同引用类型,仅可调用本身类型中所声明的方法
常见关系
类与类:
- 单继承
- extends 父类名称
类与接口:
- 多实现
- implement 接口名称1,接口名称2,接口名称3
接口与接口:
- 多继承
- extends 父接口1,父接口2,父接口3
常量接口
将多个常用于表示状态或固定值的变量,以静态常量的形式定义在接口中统一管理,提高代码可读性
#### 什么是接口
宏观概念:接口是一种标准
回调原理
接口回调:先有接口的使用者,后有接口的实现者
接口的好处
- 程序的耦合度降低
- 更自然的使用多态
- 设计与实现完全分离
- 更容易搭建程序框架
- 更容易更换具体实现
总结
-
什么是接口
微观:接口是一种能力和约定
宏观:接口是一种标准
-
接口与类的异同
没有构造方法,仅可定义公开静态常量与公开抽象方法
-
接口的应用
Java为单继承,当父类的方法种类无法满足子类需求时,可实现接口扩充子类能力
-
接口的规范
任何类在实现接口时,必须实现接口中所有的抽象方法,否则此类为抽象类
实现接口中的抽象方法时,访问修饰符必须是public
-
什么是常量接口
将多个常用于表示状态或固定值的变量,以静态常量的形式定义在接口中统一管理
-
什么是接口回调
先有接口的使用者,后有接口的实现者
第五天
面试题
1、字符串有常量池 所有字符串都会存储在堆里面的字符串常量池中
(JDK1.8 字符串常量池从原本方法区中迁徙到堆中)
2、面试题:String a=new String(“a”) 会创建几个对象
1~2个 因为有new关键字会在堆中创建一个空间
如果字符串常量池中没有"a"就会在常量池中再创建一个空间
如果已经有了就不再创建,所以创建的对象是1~2个
字符串的创建每次都会扫描字符串常量池,看是否有这个值的存在
如果没有就创建有就直接使用自己创建的字符串
字符串拼接符
String c = "a" + "b";
String b = "ab";
System.out.println(c==b);//true
Java中有常量优化机制
编译器将这个"a"+"b"作为常量表达式,在编译时进行优化,取表达式结果"ab”
这里没有创建新的对象,而是从JVM字符串常量池中获取之前已经存在的"ab"对象
因此c,b具有对同一个string对象的引用,两个引用相等,结果true。
等同于
String c = "ab";
String b = "ab"
System.out.println(c==b);//true
String a = "a";
a = a + "b";
String b = "ab";
System.out.println(a==b);//false
输出结果为:false
为什么结果为false呢?
由此可见常量优化只是针对常量,如果有变量的话就不能被优化
对.class文件进行反编译
String a = "a";
a = (new StringBuilder(String.valueOf(a))).append("b").toString();
String b = "ab";
System.out.println(b == a);
a=a+“b” 变成了 a = (new StringBuilder(String.valueOf(a))).append(“b”).toString(); 这个
+号拼接有个字符串变量,在编译的时候就会出现new StringBuilder();
内存地址经过堆的空间和直接在字符串常量池的内存地址不一样
我的理解:
因为String是一个不可变的字符序列
做了如下三步操作
2、先将String类型转换成StringBuilder类型可变字符序列
3、在StringBuilder后追加子串
4、调用toString转为String类型
过了一遍StringBuilder后 StringBuilder底层是一个默认长度为16的char数组
只要含有变量的连接(拼接) 都会采用append进行追加子串
有一个new StringBuilder的过程
网上解答:
a = a + “b”;这一句话,是在StringBuffer缓冲区中进行创建一个StringBuffer对象,将两者相加。
但是对a进行赋值时不能够直接将缓冲区的对象地址取来而是用toString方法变成另外的堆内存,
然后赋值给a,所以,a和b的地址值已经不同了,所以输出false。
第六天
内部类
内部类的分类
内部类分为:成员内部类、静态内部类、局部内部类、匿名内部类
什么是内部类
概念:在一个类的内部再定义一个完整的类
特点:
- 编译之后可生成独立的字节码文件
- 内部类可直接访问外部类的私有成员,而不破坏封装
- 可为外部类提供必要的内部功能组件
成员内部类
在类的内部定义,与实力变量、实例方法同级别的类
外部类的一个实例部分,创建内部类对象时,必须依赖外部类对象
- Outer out = new Outer();
- inner in = out.new Inner();
当外部类、内部类存在重名属性时,会优先访问内部类属性
成员内部类不能定义静态成员
静态内部类
不依赖外部类对象,可直接创建或通过类名访问,可声明静态成员
只能直接访问外部类的静态成员(实例成员需实例化外部类对象)
- Outer.Inner inner = new Outer.Inner();
- Out.Inner.show();
局部内部类
定义在外部方法中,作用范围和创建对象范围仅限于当前方法
局部内部类访问外部类当前中的局部变量时,因无法保障变量的生命周期与自身相同,变量修饰为final
限制类的使用范围
匿名内部类
没有类型的局部内部类(一切特征都与局部内部类相同)
必须继承一个父类或者实现一个接口
定义类、实现类、创建对象的语法合并,只能创建一个对象
- 优点:减少代码量
- 缺点:可读性较差
Object类
超类、基类,所有类的直接或间接父类,位于继承树的最顶层
任何类,如果没有书写extends显示继承某个类,都默认直接继承Object类,否则为间接继承
Object类中所定义的方法,是所有对象都具备的方法
Object类型可以存储任何对象:
- 作为参数,可接收任何对象
- 作为返回值,可返回任何对象
getClass()方法
public final Class<?> getClass(){}
返回引用中存储的实际对象类型
应用:通常用于判断两个引用中实际存储对象类型是否一致
hashCode()方法
public int hashCode(){}
返回该对象的十六进制的哈希码值
哈希算法根据对象的地址或字符串或数字计算出来的int类型的数值
哈希码并不唯一,可保证相同对象返回相同哈希码,尽量保证不同对象返回不同哈希码
toString()方法
public String toString(){}
返回该对象的字符串表示(表现形式)
可以根据程序需求覆盖该方法,如:展示对象各属性值
equals()方法
public boolean equals(Object obj){}
默认是实现为(this == obj),比较两个对象地址是否相同
可进行覆盖,比较两个对象的内容是否相同
equalse方法覆盖
1、比较两个引用是否指向同一个对象。
if(this == obj){
return true;
}
2、判断obj是否为null。
if(obj == null ){
return false;
}
3、判断两个引用指向的实际对象类型是否一致。
if(this.getClass() != obj.getClass()){
return false;
}
4、强制类型转换。
Worker w = (Worker)obj
5、依次比较各个属性值是否相同。
if(this.name.equals(w.name) && this.age == w.age && this.salary == w.salary){ return true;}
finalize()方法
当对象被判定为垃圾对象时,由jvm自动调用此方法,用以标记垃圾对象,进入回收队列
垃圾对象:没有有效引用指向此类对象时,为垃圾对象
垃圾回收:由GC销毁垃圾对象,释放数据存储空间
自动回收机制:JVM的内容耗尽,一次性回收所有垃圾对象
手动回收机制:使用System.gc();通知JVM执行垃圾回收
包装类
基本数据类型所对应的引用数据类型
Object可统一所有数据,包装类的默认值是null
包装类对应
基本数据类型 | 包装类型 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
boolean | Boolean |
char | Character |
类型转换与装箱、拆箱
8中包装类提供不同类型间的转换方式:
- Number父类中提供的6个共性方法
- parseXXX()静态方法
- valueOf()静态方法
注意:需保证类型兼容,否则抛出NumberFormatException异常
JDK5.0之后,自动装箱、拆箱。基本数据类型和包装类自动转换
#### 整数缓冲区
Java预先创建了256个常用的整数包装类型对象
在实际应用当中,对已创建的对象进行复用
String类
字符串是常量,创建后不可改变
字符串字面值存储在字符串池中,可以共享
String s = “Hello”;产生一个对象,字符串池中存储
String s = new String(“Hello”);//产生两个对象 堆、池各存储一个
常用方法
public char charAt(int index):根据下标获取字符
public boolean conatins(String str):判断当前字符串中是否包含str
public char[] toCharArray():将字符串转换成数值
public int indexOf(String str):查找str首次出现的下标,存在,则放回该下标;不存在,则返回-1
public int lastIndexOf(String str):查找字符串在当前字符串中最后一次出现的下标索引
public int length():返回字符串的长度
public String trim():去掉字符串前后的空格
public String toUpperCase():将小写转成大写
public boolean endWith(String str):判断字符串是否以str结尾
public String replace(char oldChar,char newChar):将旧字符串替换成新字符串
public String[] split(String str):根据str做拆分
可变字符串
StringBuffer:可变字符串,JDK1.0提供,运行效率慢、线程安全
StringBuilder:可变长字符串,JDK5.0提供,运行效率快、线程不安全
StringBuiler扩容机制:默认长度为16 满了之后 (原长度*2+2)(value << 1 +2);
BigDecimal
位置:java.math包中
作用:精确计算浮点数
创建方式:BigDecimal bd = new BigDecimal(“1.0”);
方式:
- BigDecimal add(BigDecimal bd) 加
- BigDecimal subtract(BigDecimal bd) 减
- BigDecimal multiply(BigDecimal bd) 乘
- BigDecimal divide(BigDecimal bd) 除
除法:BigDecimal(BigDecimal bd, int scal,RoundingMode mode)
参数scal:指定精确到小数点后几位
参数mode:
指定小数部分的取舍模式,通常采用四舍五入的模式,
取值为BigDecimal.ROUND_HALF_UP
Date
Date表示特定的瞬间,精确到毫秒
Date类中表示的大部分方法都已被Calendar类中的方法所取代
时间单位:
1秒=1000毫秒
1毫秒=1000微秒
1微秒=1000纳秒
Calender
Calender提供了获取或设置各自日历字段的方法
protected Calender构造方法位protected 修饰无法直接创建该对象
- static Clalendar getInstance() 使用默认时区和区域获取日历
- void set(int year,int month, int date, int hourofday,int minute, int second) 设置日历的年、月、日、时、分、秒
- int get(int field) 返回给定日历字段的值。字段比如年、月、日等
- void setTime(Date date) 用给定的Date设置此日历的时间 Date-Calender
- Date getTime() 返回一个Date表示此日历的时间 Calender-Date
- void add(int field,int amount) 按照日历的规则,给指定字段添加或减少时间量
- long getTimelnMillies() 毫秒为单位返回该日历的时间值
SimpleDateFormat
SimpleDateFormats是以与语言环境有关的方式来格式化和解析日期的类
进行格式化(日期->文本)、解析(文本->日期)
常用的时间模式字母
字母 | 日期或时间 | 示例 |
---|---|---|
y | 年 | 2021 |
M | 年中月份 | 09 |
d | 月中天数 | 12 |
H | 1天中小时数(0-23) | 22 |
m | 分钟 | 16 |
s | 秒 | 59 |
S | 毫秒 | 367 |
System类
System系统类,主要用于获取系统的属性数据和其他操作
static void arraycopy() 复制数组
staticlong currentTimeMillis() 获取当前系统时间、返回的是毫秒值
static void gc() 建议JVM赶快启动垃圾回收器回收垃圾
static void exit(int status) 退出JVM,如果参数是0表示正常退出JVM非0表示异常退出JVM
总结
-
内部类
在一个类的内部再定义一个完整的类
成员内部类、静态内部类、局部内部类、匿名内部类
-
Object类
所有类的直接或间接父类、可存储任何对象
-
包装类
基本你数据类型所对应的引用数据类型,可以使Object统一所有数据
-
String类
字符串常量,创建之后不可改变,字面值保存再字符串池中,可以共享
-
BigDecimal
可精确计算浮点数
-
时间相关类:Date、Calender、SimpleDateFormat、System