一,继承:面向对象的三大继承之一
子类 | 派生类 : 继承父类的类
定义子类独有的内容
父类 | 超类 | 基类 : 被子类继承的类
所有子类的共性
1,Q&A
1.为什么要使用继承 ?
为了提供代码的复用性
2.如何实现继承?
子类 extends 父类
class Fu{
}
class Zi extends Fu{//Zi类继承了Fu类
}
3.继承的作用 ?
子类一旦继承父类,就有权直接使用父类中的成员
public class Class001_Extends {
public static void main(String[] args) {
Teacher teacher = new Teacher("张三",33,"数学");
teacher.sleep();
teacher.teach();
}
}
//父类
class Person{
public String name;
public int age;
public Person(){}
public void sleep(){
System.out.println(name+"正在休息...");
}
}
//子类
class Teacher extends Person{
public String subject;
public Teacher(){}
public Teacher(String name,int age,String subject){
this.name = name;
this.age = age;
this.subject = subject;
}
public void teach(){
System.out.println("教书育人...");
}
}
4.注意 : 继承是单继承机制,但是接口可以多实现
一个子类只能存在一个直接父类
一个父类可以存在多个子类
5.单继承的优缺点 : 简单,但是不便于后期维护
2,this与super
this : 指代当前对象(new|调用成员方法的对象)
在构造器的首行通过this(实参)调用本类中的其他构造器
区分同名成员与局部变量问题
默认就近原则找局部
想要指代成员,需要通过this.调用成员
如果不存在同名问题,调用成员时,this.可以省略
//成员变量
private String name;
private int age;
//带参构造器
public Student(String name,int age){
this.name=name;
this.age=age;
}
super :指代父类对象
在子类构造器的首行通过super(实参)调用父类构造器
如果在子类构造器的首行没有通过super(实参)显示的调用父类的指定构造器,默认会调用父类空构造 super()
不能在子类构造器的首行同时通过this(实参)与super(实参)调用其他构造器,可以先执行this(实参),调用本类中其他构造器后,在其他构造器的首行通过super(实参)调用父类构造器
默认就近原则找子类的成员
通过super.调用的父类成员
成员的初始顺序 : 先静态后成员
子父类继承关系下创建子类对象 : 先父类后子类
public class Fu{
String str="Fu类str";
}
public class Zi extends Fu{
String str="子类str";
public void test(){
String str="局部str";
System.out.println(str); //局部
System.out.println(this.str); //子类成员str
System.out.println(super.str); //父类str
System.out.println(this);
}
}
this与super都不能使用在static修饰的方法中
3,重写 override
3.1 重写与重载之间的区别 :
3.1.1.共同点 : 都是方法的重要特性
3.1.2.异同点 :
3.1.2.1实现重载的3个条件 :
1.一个类中的多个方法
2.方法名相同
3.参数列表|方法签名不同(方法签名:方法名+参数列表;是方法唯一的标识)
public class Student{
//一个参数的构造器
public void Student(String name){
this.name=name;
}
//两个参数的构造器
public void Student(String name,int age){
this.name-name;
this.age=age;
}
}
3.1.2.2实现重写的3个条件 :
1.两个类中的两个方法
2.继承关系|实现关系
3.方法签名完全相同(方法签名:方法名+参数列表 ,是方法的唯一标识)
public class Class001_Override {
public static void main(String[] args) {
SiCong siCong = new SiCong();
siCong.words();
}
}
class JianLin{
public String name = "王健林";
//名言
public JianLin words(){
System.out.println("先定一个小目标,挣它一个亿....");
return null;
}
}
class SiCong extends JianLin{
public String name = "王思聪";
//重写
@Override
public SiCong words(){
System.out.println("我不在乎我的朋友有钱没钱,反正都没我有钱!!!!");
return null;
}
}
3.2 重写方法的定义需求 :
子类从父类中继承功能(方法),方法满意,方法体实现子类不满意,就可以在子类中对这个方法进行重新实现--->方法的重写
3.3 方法的调用 :
通过子类对象,调用子类中重写的方法,对父类中的被重写的方法进行屏蔽
如果没有重写方法,会顺着继承体系,到父类中查找,如果都没有,会报错
3.4 如何检查方法是否为重写方法 :
1.行号的后面显示O+箭头,点击跳转到重写方法|被重写方法上
2.重写方法上添加一个注解: @Override
3.5 重写方法的细节要求 :
== : 方法签名要求完全相同
<= : 返回值类型 :
基本数据类型|void : 返回值类型要求完全相同
引用数据类型 : 子类中的重写方法的返回值类型<=父类中的被重写方法的返回值类型
>= : 权限修饰符 : 子类中重写的权限修饰符>=父类中被重写方法的权限修饰符
3.6 注意 :
继承 : 延续+扩展
不能被重写的方法 :
1.被private修饰的方法不能被重写
2.被final修饰的方法不能被重写
3.被static修饰的方法不能被重写
如果子类中出现于父类静态方法同名的方法,要求也要被static修饰
二,封装
1.访问权限修饰符 :
控制被修饰的成员被访问的权限
成员修饰符,只能修饰成员不能修饰局部
分类 | 本类中 | 同包类 | 不同包下子类 | 其他类 |
public 公共的 | √ | √ | √ | √ |
protected 受保护的 | √ | √ | √ | |
default 默认的(省略) | √ | √ | ||
private 私有的 | √ |
可以修饰类的访问权限修饰符为 : public default
最常用的两个访问权限修饰符 : public private
protected修饰的成员的使用 :
1)同包下类使用
2)在不同下的子类中,通过继承关系访问
package homework.homework0223.modifier;
public class Class001_Modifier {
public String testPublic="public";
private String testPrivate="private";
protected String testProtected="rotected";
String testDefault="default";
public static void main(String[] args) {
//测试本类中能否使用
Class001_Modifier cm=new Class001_Modifier();
System.out.println(cm.testPublic);
System.out.println(cm.testDefault);
System.out.println(cm.testPrivate);
System.out.println(cm.testProtected);
}
}
//同包类
class Demo{
public static void main(String[] args) {
//测试同包类
Class001_Modifier cm=new Class001_Modifier();
System.out.println(cm.testPublic);
System.out.println(cm.testDefault);
//protect只能在同类下使用
//System.out.println(cm.testPrivate);
System.out.println(cm.testProtected);
}
}
import com.yjxxt.modifier02.Class001_Modifier;
//不同包下的子类
public class OtherSon extends Class001_Modifier {
public static void main(String[] args) {
//1)不同包下的子类中使用 2)通过父类对象访问-->不能访问父类中被protected修饰的成员,因为不是通过继承关系访问
Class001_Modifier cm = new Class001_Modifier();
System.out.println(cm.testPublic);
//1)不同包下的子类中使用 2)通过子类对象访问
OtherSon son = new OtherSon();
System.out.println(son.testPublic);
System.out.println(son.testProtected);
}
//成员方法
public void test(){
System.out.println(testPublic);
//1)不同包下的子类中使用 2)通过继承关系
System.out.println(testProtected);
}
}
//不同包下的其他类
class Other{
public static void main(String[] args) {
//测试不同包下的其他类中使用
Class001_Modifier cm = new Class001_Modifier();
//System.out.println(cm.testPrivate);
//System.out.println(cm.testDefault);
//System.out.println(cm.testProtected);
System.out.println(cm.testPublic);
}
}
面向对象的设计原则之一 : 开闭原则 (对修改关闭,对扩展开放)
三,多态
多态 : polymorphic --> 面向对象三大特性之一
一种事物的多种形态|多种表现形式|多种实现方式
行为多态 : 一个功能的不同实现方式
1.多态的最终体现 :
父类的引用指向子类对象
public static void main(String[] args){
//父类引用指向子类对象,发生了多态
Fu fu=new Zi();
}
class Fu{
}
class Zi extends Fu{
}
2.多态的前提 :
继承关系|实现关系
3.多态调用 :
多态引用调用会调用子类中重写的方法,对子类新增内容不可见
多态调用成员变量 : 编译运行看父类|左边|类型
多态调用成员方法 : 编译看父类|左边|类型,运行看子类|右边|对象
一个有趣的测试题帮助理解
/*
* 做题四大原则:
* 一、继承链:自己没有找父类
* A
* |
* B
* / \
* C D
* 二、 编译看类型、确定方法,运行找对象
*
* 三、就近最优原则
*
* 四、父类引用对子类新增方法不可见
*/
public class Class002_PolyTest {
public static void main(String[] args) {
A a1=new A(); //A and D A and A
//多态
A a2=new B(); //A and D B and A
B b =new B(); //A and D B and A B and B
C c=new C();
D d =new D();
System.out.println(a1.show(b)); //A and A
System.out.println(a1.show(c)); //A and A
System.out.println(a1.show(d)); //A and D
System.out.println(a2.show(b)); //B and A
System.out.println(a2.show(c)); //B and A
System.out.println(a2.show(d)); //A and D
System.out.println(b.show(b)); //B and B
System.out.println(b.show(c)); //B and B
System.out.println(b.show(d)); //A and D
}
}
class A{
public String show(D obj){
return ("A and D");
}
public String show(A obj){
return ("A and A");
}
}
class B extends A{
//新增方法-->多态引用肯定无法调用
public String show(B obj){
return ("B and B");
}
public String show(A obj){
return ("B and A");
}
}
class C extends B{
}
class D extends B{
注意 :
标准的赋值 : 对应类型的数据赋值给对应类型的变量
int i=1;
多态使用需要配合方法的重写才有意义
四,类型转换
1,标准 : 对应类型的数据赋值给对应类型变量
int i = 1;
2,基本数据类型的类型转换
自动类型提升 : 小--->大
long l = i;
强制类型转换 : 大--->小,有可能造成损失精度(不精确)-->需要手动进行强转
int i2 = (int)l;
3,转型 : 引用数据类型的类型转换
父类-->大
子类-->小
3.1当前后类型不一致 :
3.1.1 向上转型 : 小 --> 大 -->多态
Person p = new Student();
3.1.2 向下转型 : 向下转型对象不变,引用从父类类型转为子类类型,就可以调用子类中所有的成员(子类新增)
Student s = (Student)p;
3.类型转换异常
java.lang.ClassCastException : 类型转换异常
使用instanceof运算符在转型之前先判断,再转型,避免类型转换异常的出现
引用 instanceof 类型 : 判断前面的引用是否是指向后面类型的对象或者子类对象对象,如果是返回true,不是返回false
public class Class001_Cast {
public static void main(String[] args) {
Fu f = new Zi();
//向下转型
if(f instanceof Zi2){
Zi2 zi = (Zi2)f;
zi.test();
}else if(f instanceof Zi){
Zi zi = (Zi)f;
zi.test();
}
}
}
class Fu{}
class Zi extends Fu{
void test(){
System.out.println("Zi--test");
}
}
class Zi2 extends Fu{
void test(){
System.out.println("Zi2--test");
}
}