Java SE 面向对象 多态
目录
1.、访问控制符
指被不同权限修饰符修饰的内容能够被使用的范围
关键字 | 本类 | 同个包中 | 不同包的子类 | 所有类 |
---|---|---|---|---|
private | √ | |||
default | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
注意:
-
使用最多的private,public
-
能够修饰类的权限修饰符: public ,default(默认的省略不写)
-
都是成员修饰符,只能修饰成员,不能修饰局部
-
不能在外部调用一个作用域中的局部内容(局部变量)
在不同包下的子类中,如果想要使用父类中被protected修饰的成员,需要通过继承关系使用(直接在子类使用有权限的父类成员,或者通过子类对象使用).不能通过父类对象是使用
2、方法重写(override)
在子类继承父类后,继承了一写功能方法,有些功能,功能的实现不满意,可以进行功能的重写(重新实现)
重写定义方法体:
- 不同的两个类
- 继承关系|实现关系
- 方法签名相同(方法名+参数列表)
使用:
-
子类一旦重写方法,子类对象调用的时候,就会发生就近原则,对父类方法进行屏蔽
-
子类对象调用功能时候,子类存在找子类,子类没有找父类
== <= >=满足的条件:
- == : 方法签名完全相等
- <= : 返回值类型为基本数据类型要求完全相等,如果为引用数据类型,子类方法返回值类型<=父类方法的返回值类型
- >= : 权限修饰符: 子类方法的权限修饰符>=父类方法的权限修饰符
检查是否为重写方法:
- 1.@Override 强制检查是否为重写方法,不是报错
- 2.工具中方法的左侧有提示
不能被重写的方法:
- 1.被private关键字修饰的方法不能被重写
- 2.被final关键字修饰的方法不能被重写
- 3.被static关键字修饰的方法不能被重写
当子类中出现于父类静态方法同名的方法时候,子类的同名方法也要是静态的,否则报错,但是不是重写方法
public class OverrideDemo02 {
public static void main(String[] args) {
ErEr er=new ErEr();
System.out.println(er.name);
// 调用 父类
er.test();
er.run();
}
}
class YeYe{
String name="YeYe";
public void test(){
System.out.println("Yeye");
}
}
class BaBa extends YeYe{
String name="baba";
// 重写test方法
public void test(){
System.out.println("baba");
}
public void run(){
System.out.println("名言");
}
//静态方法
public static void haha(){
System.out.println("haha");
}
}
class ErEr extends BaBa {
String name="erer";
//重写父类方法
public void run(){
System.out.println("都没我有钱");
}
}
3、Object 类
老祖宗类 java.lang
- java中所有类的父类
- java中的所有类都会直接|间接的继承自Object类
- 如果没有显示的继承自某个类型,默认会继承Object
ctrl+n->查询某个类
public class Person { ... }
等价于 :
public class Person extends Object { ... }
3.1 equals ()方法
1、equals() 比较两个对象是否相等(默认使用==比较,比较对象地址)
如果想要实现比较对象内容,而非地址值,需要在子类中重写equals方法,需要自己实现比较内容(成员属性的值)
public boolean equals(Object obj) {
return (this == obj);
}
== :
比较基本数据类型: 比较数据值
比较引用数据类型: 比较两个对象的地址是否相等
注意:
- 认为两个对象,如果所有成员属性的值都想等,就应该是一个对象
- 在java中只要通过new关键字创建的对象,无论成员属性值是否相等,地址都不相等,如果比较地址,都不相等,所以引用数据类型对象的时候,不让它默认比较地址,手动让她比较内容
public class ObjectDemo01 {
public static void main(String[] args) {
Fu fu = new Fu();
Fu fu2 = fu;
System.out.println(fu == fu2); //true
System.out.println(fu.equals(fu2)); //true
String str1 = "zhangsan";
String str2 = "zhangsan";
System.out.println(str1.equals(str2)); //true
Person1 p1 = new Person1("haha",20,1001);
Person1 p2 = new Person1("haha",30,1001);
System.out.println(p1 == p2); //比较地址 false
System.out.println(p1.equals(p2)); //比较num内容 true
System.out.println(p1.equals(new String())); //比较地址 false
}
}
class Fu{}
class Zi extends Fu{}
public class Person1 {
public String name;
public int age;
public int num; //身份证号
//空构造
public Person1(){ }
public Person1(String name,int age,int num){
this.name = name;
this.age = age;
this.num = num;
}
//重写equals 要求: 只比较两个人的身份证号决定两个Person是否相等
public boolean equals(Object obj) {//Object obj = new Person("yinwei",20,1001); 多态引用只能调用父类中存在的成员
//获取当前对象的num
int num1 = this.num;
//获取参数对象的num
if(obj instanceof Person1){
Person1 p = (Person1)obj;
int num2 = p.num;
if(num1==num2){
return true;
}
}
return false;
}
}
3.2 toString() 方法
-
toString() 以字符串的形式表示当前对象
-
Object类中的toString默认返回当前对象类型的包名.类名@十六进制的地址值
-
如果想要打印对象的成员变量的值不想打印对象地址,可以在子类中对toString方法进行重写
-
注意:
当**打印一个对象的引用的时候,默认会调用toString,**打印的是当前对象调用了toString之后的返回值。
ublic class ToStringDem06 {
public static void main(String[] args) {
Student s1 = new Student();
Student s2 = new Student();
s1.name = "zhangsan";
s1.age = 19;
System.out.println(s1);
System.out.println(s1.toString());
}
}
class Student{
public String name;
public int age;
//需求:打印对象引用时候,输出当前对象的所有成员变量的值
public String toString(){
return name+"-->"+age;
}
}
4、多态
一种事物的多种形态|多种表现形式
- 多态的前提: 继承|实现
- 多态的最终体现: 父类的引用指向子类的对象
//多态 父类引用指向子类对象
Baa ba2 =new Zii();
3.1 使用
当父类类型的引用调用成员时候:
成员变量: 编译运行看父类|左边|类型
成员方法:
编译看父类|类型|左边
运行时找父类方法,方法被重写找子类
当通过父类的引用调用成员方法时候,如果 子类有重写方法就调用重写的, 如果没有找父类
如果多态不配合方法的重写,多态也没有意义
public class PolymerDemo03 {
public static void main(String[] args) {
Baa baa=new Baa();
Zii zii =new Zii();
//多态 父类引用指向子类对象
Baa ba2 =new Zii();
//调用 父类 属性
System.out.println(ba2.name);
//调用子类重写方法
//多态不配合方法的重写,多态也没有意义
ba2.test();
//父类自己方法
ba2.test1();
}
}
class Baa{
String name="Baba";
public void test(){
System.out.println("父类哈哈");
}
public void test1(){
System.out.println("第二bab类");
}
}
class Zii extends Baa{
String name="zii";
public void test(){
System.out.println("子类哈哈");
}
}
3.2 向上转型和向下转型
基本数据类型的类型转换 == 引用类型的类型提升
- 向上转型 : 自动类型提升
从小到大->从子类到父类
父类类型 引用 = new 子类类型();
long l = 1;
//多态 向上转型
Die die=new Zi();
- 向下转型 : 强制类型转换
从大到小 ->从父类到子类
小范围类型 变量 = (小范围类型)大范围类型的数据;
int i = (int)l;
向下转型可能遇到类型转换异常ClassCastException:
-
引用 instanceof 类型
判断前面的引用是否指向后面类型的对象,或者是否指向后面类型子类的对象,如果是返回true,不是返回false//转型之前的判断: 为了预防类型转换异常的出现 引用 instanceof 类型 //向下转型 Zi zi =(Zi)die;
public class CastDemo04 {
public static void main(String[] args) {
//多态 向上转型
Die die=new Zi();
System.out.println(die.name);
die.run();
//转型之前的判断: 为了预防类型转换异常的出现 引用 instanceof 类型
//向下转型
Zi zi =(Zi)die;
zi.play();
zi.run();
System.out.println(die instanceof Die); //false
System.out.println(die instanceof Zi); //true
//System.out.println(die instanceof KongZiDie); //true
}
}
class Die {
String name="Die";
public void run(){
System.out.println("Die");
}
}
class Zi extends Die{
String name="Er";
public void run(){
System.out.println("Er");
}
public void play(){
System.out.println("yuanshen");
}
}
3.3 多态与继承联系
- 多态:成员变量看父类,方法看父类,子类重写看子类
- 继承:继承父类变量和方法,子类重写看子类
四大原则 :
- 一、继承链:自己没有找父
- 二、 编译看类型、确定方法,运行找对象
- 三、就近最优原则
- 四、父类引用对子类新增方法不可见
public class PolyTest05 {
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();//B and B B and A A and D
C c=new C();//B and B B and A A and D
D d =new D();//B and B B and A A and 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{
}
5、abstract 抽象的
-
抽象类: abstract修饰的类
-
抽象方法: 被abstract修饰的方法
- 可以没有方法体
- 必须存在与抽象类中
注意:
-
1.抽象类不能够实例化
-
2.抽象方法必须存在抽象类中
-
3.抽象类中可以存在抽象方法,可以存在普通的具体方法,可以存在成员,构造器…
-
4.抽象方法必须要被重写才能使用
-
5.抽象方法只要被重写就可以使用,不需要再次重写,可以根据需求进行重写
-
6.抽象类使用: 通过具体子类的对象调用
- 1.普通的子类: 需要重写所有抽象方法+按需新增
- 2.抽象子类: 按需重写抽象方法+按需新增
-
7、abstract 不能与private,static,final,native同时存在
public abstract class Develop01 {
//工作 方法体不确定些什么,不确定怎么写,那就不写
public abstract void work1();
public abstract void work2();
//普通方法
public void sleep(){
System.out.println("边工作边休息...");
}
}
/*
java攻城狮
普通的子类|具体的子类(没有被abstract修饰的类)
*/
public class Java extends Develop{
//对父类中继承的抽象方法进行重写实现
@Override
public void work1() {
System.out.println("JAVA按照规矩办事!!!");
}
@Override
public void work2() {
System.out.println("JAVA做后端开发...");
}
//形象 -->新增方法
public void xingxiang(){
System.out.println("没头发了!!!!又该植发了!!!!!");
}
}
public class AbsTest {
public static void main(String[] args) {
//抽象类不能实例化
//Develop de = new Develop();
//具体子类的使用
Java java = new Java();
java.work1();
java.work2();
java.xingxiang();
java.sleep();
//抽象类的多态 : 向上转型
//只能调用develop类中的功能
Develop d = new Java();
d = new Web2();
}
}