一,封装
生活的封装体:包装盒、机箱
代码中封装体:包、类、方法
好处:
提高了代码的复用性
提高了代码的安全
隐藏了实现的细节
属性的封装:
问题:在对属性进行赋值时,只要赋的值是符合该类型的任何值都是可以完成赋值动作,但是赋的值可能的合法的值。
原因:
只要有对象就可以随意的对属性进行调用
对属性进行赋值时没有对数据进行合理性的判断
解决:
使用关键字
private
将属性私有化对外提供这个私有化属性的访问方法
赋值:
public void setName(String name) { this.name = name; }获取:
public String getName() { return name; }一个标准的实体类必须包含:
无参的构造函数
私有化的属性
对外提供访问私有属性的
set/get
方法注:如果属性的类型的布尔类型,那么需要对外提供的是
set/is
方法public boolean isSex() { return sex; } public void setSex(boolean sex) { this.sex = sex; }
二,继承
2.1 继承的概念
生活中的继承:子女拥有父母的东西
代码中的继承:类与类之间产生了关系,子类可以直接使用父类中的成员
父类是子类中共性内容的向上抽取,子类中除了有父类中的共性内容之外还可以有特性内容
父类:superclass,超类、基类
父类的范围一般比较大,属性和方法一般比较少
子类:subclass,派生类、衍生类
子类的范围一般更加精准,属性和方法也比较多
Java中定义了一个类
Object
,这个类是所有类的父类(任何一个类都直接或者间接的继承了Object)一个子类就是一个父类
好处:
提高代码的复用性
为多态提供了前提
2.2 父类和子类的定义
关键字:
extends
父类:
public class 父类名{ }子类:
public class 子类名 extends 父类名{ }注:
一个子类只有一个直接父类
一个父类可以有多个子类
继承具有传递性
2.3 子父类中成员的同名问题
2.3.1 同名变量
子父类中存在同名成员变量时,创建子类对象,优先访问子类中的。
如果要访问父类中的同名成员变量,需要在子类中通过关键字
super
进行访问。class Fu{ int i = 3; } class Zi extends Fu{ int i = 4; public void f(){ System.out.println("this的地址:"+this); int i = 6; System.out.println(i);//6 System.out.println(this.i);//4 System.out.println(super.i);//3 } }
2.3.2 同名方法
子父类中存在同名成员方法时,创建子类对象,优先访问子类中的。
如果要访问父类中的同名成员方法,需要在子类中通过关键字
super
进行访问。方法的重写:
子类中方法名和父类中的方法名相同
参数列表和父类方法的参数列表相同
重写的作用:扩展父类的功能
注:
子类重写父类方法的范围修饰符必须大于等于父类
public > protected > [defalut]默认不写 > private
子类重写父类方法的返回类型必须是父类方法的返回类型或者该类型的子类
注解
@Override
,可以用于校验当前方法的定义是否是在重写
2.4 父类属性私有化问题
子类的共性属性抽取到了父类中,父类属性私有化了,子类不能直接访问,可以通过父类对外提供的
set/get
方法进行访问。
如何使用构造函数的重载,在创建子类对象时,对子类的属性进行初始化?
步骤:
重载父类构造函数
在子类的重载构造函数中调用父类的重载构造函数
// 父类 public class Emp { private String name; private int age; private double salary; public Emp(){ } public Emp(String name, int age, double salary) { this.name = name; this.age = age; this.salary = salary; } } //子类 public class Seller extends Emp{ public Seller(){ } public Seller(String name,int age,double salary){ super(name,age,salary); } }
三,抽象类
3.1 概念
抽象方法:子类的共性方法抽取到父类中,而父类无法描述每个子类的具体实现时,这样的方法就是抽象方法,抽象方法要使用关键字
abstract
修饰方法,并且抽象方法没有方法体。抽象类:抽象方法所在的类必须是抽象类
3.2 抽象类的使用
抽象类不能创建对象,所以必须要有子类,除非子类重写父类中的所有抽象方法,否则子类也是一个抽象类
步骤:
定义抽象类的子类
重写所有抽象方法
创建子类对象进行调用
3.3 注意事项
抽象类不能创建对象
抽象类有构造函数
抽象类可以非抽象方法
不能与
abstract
共存的修饰符关键字:final、static
3.4 关键字 final
可以修饰:
变量:不能再被赋值
注:成员变量用
final
修饰,必须初始化方法:不能被重写
类:不能被继承
3.5 匿名对象
创建对象时,不指定对象的引用变量名
好处:
使用方便
弊端:
只能使用一次
可读性差
3.6 匿名内部类
使用匿名的方式创建一个类的子类对象
格式:
new 类名(){ // 重写方法 };new Animal(){ @Override public void eat() { // } @Override public void sleep() { // } };
四,接口
4.1 接口的概念
接口是一种特殊的类,它在编译后生成的也是
.class
的文件,接口是功能的集合好处:
对外提供了规则
接口扩展了功能
4.2 接口的定义
关键字:
interface
格式:
public interface 接口名{ }
4.3 接口中成员的特点
接口中成员方法的特点:默认被
public abstract
修饰接口中成员变量的特点:默认被
public static final
修饰
4.4 接口的使用
关键字:
implements
步骤:
创建实现类实现接口
public class Mouse implements Usb{}重写所有抽象方法
创建实现类对象调用
接口也可以使用匿名内部类的方式创建实现类对象
格式:
new 类名/接口名(){ // 重写方法 };new Usb(){ @Override public void connect() { System.out.println("设备已连接"); } }.connect();
4.5 类、接口之间的关系
4.5.1 类与类的关系
类与类的关系是继承:子类继承父类
public class 子类 extends 父类{}注:类与类之间只存在单继承
4.5.2 类与接口的关系
类与接口的关系是实现:实现类实现接口
public class 实现类 implements 接口A,接口B,...{}注:一个实现类可以实现多个接口
4.5.3 接口与接口的关系
接口与接口的关系是继承:子接口继承父接口
public interface 子接口 extends 父接口A,父接口B,...{}注:一个子接口可以继承多个父接口
4.5.4 子类继承父类的同时实现接口
public class 类名 extends 类名 implements 接口{}
4.6 抽象类与接口的异同
同:
抽象类和接口都有抽象方法
抽象类和接口都不能创建对象
抽象类和接口都需要子类(实现类)继承(实现)
异:
接口中的方法都是抽象的,抽象类中可以有非抽象方法
抽象类中的成员变量与普通类中的成员变量没有区别,接口中的成员变量都是静态的常量
抽象类是class、接口是interface,继承类是extends、实现接口是implements
一个类只能继承一个抽象类,一个类可以实现多个接口
抽象类中有构造函数,接口中没有构造函数
抽象类是描述这个类的属性和方法集合,接口是功能的集合
抽象类和接口的选用:建议优先选择接口,接口避免了单继承的局限性
4.7 接口的新特性
从 Java8 开始,接口中允许定义普通方法
格式:
public default 返回类型 方法名(参数列表){ }注:
实现类可以对接口中的普通方法进行重写,重写时不能有
default
父类中的方法与接口中的普通方法同名,子类优先调用父类中的方法
意义:为了解决版本的升级问题
从 Java8 开始,接口中允许定义静态方法
public static 返回类型 方法名(参数列表){ }注:接口中的静态方法只能由定义它的接口名调用
从 Java9 开始,接口中允许定义私有方法
private 返回类型 方法名(参数列表){ }意义:为接口中的其他普通方法提供支持,但不需要对外提供
五,多态
5.1 多态的概念
前提:必须有继承或者实现的关系
一个子类就是一个父类
多态的概念:父类的引用变量指向子类对象
代码中的体现:父 Emp、子 Seller
Emp e = new Seller();
5.2 多态下,调用同名成员变量和成员方法的特点
调用成员变量的特点:
编译时期:如果父类中没有这个变量,则编译失败;父类中有这个变量编译才能通过
运行时期:访问的是父类中的变量
小结:编译运行都看左边
调用成员方法的特点:
编译时期:如果父类中没有这个方法,则编译失败;父类中有这个方法编译才能通过
运行时期:访问的是子类中的方法
小结:编译看左边,运行看右边
总结:多态下,不能访问子类的特有成员
5.3 多态的引用
场景1:
如果一个方法的形参是引用数据类型,那么实参可以是该类型或者该类型的任何一个子类/实现类
LinkedList l1 = new LinkedList(); l1.add(11); l1.add(22); l1.add(33); l1.add(44); l1.add(55); l1.add(66); System.out.println(l1); Collections.shuffle(l1); System.out.println(l1); System.out.println("~~~~~~~~~~~~~~~~~~~~~~~"); ArrayList l2 = new ArrayList(); l2.add(1); l2.add(2); l2.add(3); l2.add(4); l2.add(5); l2.add(6); System.out.println(l2); Collections.shuffle(l2); System.out.println(l2); // Collections中shuffle方法用于对集合进行打乱,shuffle方法的参数是List,形参List是一个接口,实参是可以是List接口的任何一个实现类对象
场景2:
如果一个方法的返回类型是引用数据类型,那么返回的结果可以是该类型或者它的任何一个子类/实现类
5.4 多态的转型问题
5.4.1 向上转型
多态本身就是向上转型,将子类对象赋值给父类的引用变量
弊端:多态下无法访问子类的特有内容
5.4.2 向下转型
多态下无法访问子类的特有内容,需要向下转型,才能调用
格式:
// Fu是父类/接口 Zi是子类/实现类 Fu x = new Zi(); Zi z = (Zi)x;注:如果向下转型的目标类型与多态下的类型不匹配,会发生
ClassCastExcepton
类型转换异常解决:关键字
instanceof
用法:
对象 instanceof 类型作用:判断该对象是否属于指定类型,获得布尔值