面向对象02

7.继承

  • 继承的本质是对某一批类的抽象,从而实现对现实世界更好地建模
  • extends的意思是“扩展”。子类是父类的扩展。
  • Java类中只有单继承,没有多继承!(一个儿子只能有一个爸爸,一个爸爸可以有多个儿子)
  • 继承是类和类之间的一种关系。除此之外,类和类之间的关系还有依赖、组合、聚合等。
  • 继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字extends表示
  • 子类和父类之间,从意义上讲应该具有“is a”的关系
  • object类
  • super
  • 方法重写

子类继承了父类,就会有父类的全部方法!(私有的东西无法被继承)

例子1:

package li.oop.demo05;

//父类:Person 人
public class Person { //public
//protected
//default
//private
public int money = 10_0000_0000; public void say(){
System.out.println("说了一句话");
} public int getMoney() {
return money;
} public void setMoney(int money) {
this.money = money;
}
}
package li.oop.demo05;
//学生 is 人
//派生类(子类),子类继承了父类,就会有父类的全部方法
public class Student extends Person{
}
package li.oop;

import li.oop.demo05.Student;

public class Application {
public static void main(String[] args) {
Student student = new Student();
student.say();//说了一句话
System.out.println(student.money);// 1000000000
}
}

7.1Object类

在Java中,所有的类都默认直接或者间接继承Object类

7.2Super关键字

  • super. 大部分情况下是可以省略的。

    当父中类有,子类中又有,如果想在子中访问“父的特征”,super. 不能省略。

    在父和子中有同名的属性,或者说有相同的方法,如果此时想在子类中访问父中的数据,必须使用“super.”加以区分。

    • super.属性名 --->访问父类的属性

    • super.方法名(实参) --->访问父类的方法

    • super(实参) ---->调用父类的构造方法

  • 子类继承父类,子类的构造方法必须调用super()即父类的构造方法,而且必须放在构造方法的第一行。

    子类构造方法第一行都有调用父类无参的构造方法,如果你不显示地写出了,系统会自己加上;

    但是如果你的父类重载了一个或多个构造方法,系统将不再默认加上无参的构造方法,必须自己加上。

  1. super调用父类的构造方法,必须在构造方法中的第一行
  2. super必须只能出现在子类的方法或者构造方法中
  3. super和this不能同时调用构造方法
  4. super&&this
    • 代表的对象不同:

      • this:代表本身调用者这个对象
      • 代表当前类的父类对象的引用
    • 前提:
      • this:没有继承也可以使用
      • super:只能在继承条件下才可以使用
    • 构造方法的区别:
      • this(); 本类的构造
      • super(); 父类的构造

7.3方法重写

例子1:

package li.oop.demo05;
//重写都是方法的重写,和属性无关
public class B {
public static void test(){
System.out.println("B==>test");
}
}
package li.oop.demo05;
public class A extends B{ public static void test(){
System.out.println("A==>test");
}
}
package li.oop;

import li.oop.demo05.A;
import li.oop.demo05.B; public class Application {
public static void main(String[] args) {
//静态方法:方法的调用只和左边定义的类型有关
A a = new A();
a.test();//调用的是A类方法 //父类的引用指向了子类
B b = new A();
b.test();//调用的是B类方法 }
}

静态方法:方法的调用只和左边定义的类型有关

例子2:

package li.oop.demo05;
//重写都是方法的重写,和属性无关
public class B {
public void test(){
System.out.println("B==>test");
}
}
package li.oop.demo05;

public class A extends B{
//Override 重写
@Override // 注解:有功能的注解!
public void test(){
System.out.println("A==>test");
}
}
package li.oop;
import li.oop.demo05.A;
import li.oop.demo05.B; //静态方法和非静态方法区别很大!
//静态方法:方法的调用只和左边定义的类型有关
//非静态:重写
public class Application {
public static void main(String[] args) { A a = new A();
a.test(); //父类的引用指向了子类
B b = new A();//子类重写了父类的方法
b.test();
}
}

总结:

重写 :子类的方法和父类的方法必须要一致,方法体不同

-- 重写前提:需要有继承关系,子类重写父类的方法

  1. 方法名必须相同
  2. 参数列表必须相同
  3. 修饰符:范围可扩大,但不能缩小:public>protected>default>private
  4. 抛出的异常:范围可以被缩小,但不能扩大。例如:ClassNotFoundException(范围小)-->Exception(范围大)

为什么需要重写?:父类的功能,子类不一定需要,或者不一定满足!

快捷键:Alt+insert:Override;

8.多态

8.1多态的定义和使用

  • 即同一方法可以根据发送对象的不同而采取多种不同的行为方式

  • 一个对象的实际类型是确定的,但可以指向对象的引用类型有很多

    这里的引用一般指父类或者有关系的类

  • 多态存在的条件:

    • 有继承关系
    • 子类重写父类方法
    • 父类引用指向子类对象
  • 注意:多态是方法的多态,属性没有多态性

  • instanceof (类型转换)引用类型

例子1:

package li.oop.demo06;

public class Person {
public void run(){
System.out.println("run");
}
}
package li.oop.demo06;

public class Student extends Person{

}
package li.oop;

import li.oop.demo06.Person;
import li.oop.demo06.Student; public class Application {
public static void main(String[] args) { //一个对象的实际类型是确定的
//new Student();
//new Person(); //但是可以指向的引用类型就不确定了
Student s1 = new Student();
Person s2 = new Student();//父类的引用指向子类
Object s3 = new Student();//父类的引用指向子类 s2.run();//这里虽然new的是Student,但是是它依旧走的是父类的方法,因为子类继承了父类的全部方法
}
}

这里的 s2 虽然new的是Student,但是是s2.run() 依旧走的是父类的方法,因为子类继承了父类的全部方法

例子2

package li.oop.demo06;

public class Person {
public void run(){
System.out.println("run");
}
}
package li.oop.demo06;

public class Student extends Person{
@Override
public void run() {
System.out.println("son");
} public void eat(){
System.out.println("eat");
}
}
package li.oop;

import li.oop.demo06.Person;
import li.oop.demo06.Student; public class Application {
public static void main(String[] args) { //一个对象的实际类型是确定的
//new Student();
//new Person();
//但是可以指向的引用类型就不确定了 //Sudent能调用的方法都是自己的或者继承父类的
Student s1 = new Student(); //Person父类型:可以指向子类,但是不能调用子类独有的方法
Person s2 = new Student();//父类的引用指向子类
Object s3 = new Student();//父类的引用指向子类 s2.run();//子类重写了父类的方法,执行子类的方法
s1.run(); //s2.eat 不能调用 s2为Person父类型:可以指向子类,但是不能调用子类独有的方法
((Student) s2).eat();//强制类型转换后才可以使用
//对象能够执行的方法主要看对象左边的类型和右边关系不大
}
}

对象能够执行的方法主要看对象左边的类型和右边关系不大。

//Person父类型:可以指向子类,但是不能调用子类独有的方法
Person s2 = new Student();//父类的引用指向子类
//子类Sudent能调用的方法都是自己的或者继承父类的
Student s1 = new Student();

多态注意事项:

  • 多态是方法的多态,属性没有多态
  • 父类和子类,有联系
  • 多态存在的必要条件:
    • 有继承关系
    • 方法需要重写
      • 不能重写的方法:

        • 1.static 方法,属于类,它不属于实例
        • final 常量
        • private 方法
    • 父类的引用指向子类对象

8.2instanceof

instanceof(类型转换)引用类型,判断一个对象是什么类型

例子1:

package li.oop.demo06;

public class Person {
public void run(){
System.out.println("run");
}
}
package li.oop.demo06;
public class Student extends Person{
}
package li.oop.demo06;
public class Teacher extends Person{
}
package li.oop;

import li.oop.demo06.Person;
import li.oop.demo06.Student;
import li.oop.demo06.Teacher; public class Application {
public static void main(String[] args) { //Object > Person > Student
//Object > Person > Teacher
//Object > String Object object = new Student();
System.out.println(object instanceof Student);//true
System.out.println(object instanceof Person);//true
System.out.println(object instanceof Object);//true
System.out.println(object instanceof Teacher);//false
System.out.println(object instanceof String);//false System.out.println("=============="); Person person = new Student();
System.out.println(person instanceof Student);//true
System.out.println(person instanceof Person);//true
System.out.println(person instanceof Object);//true
System.out.println(person instanceof Teacher);//false
// 编译就报错了 System.out.println(person instanceof String); System.out.println("=============="); Student student = new Student();
System.out.println(student instanceof Student);//true
System.out.println(student instanceof Person);//true
System.out.println(student instanceof Object);//true
// 编译就报错了 System.out.println(student instanceof Teacher);
//编译就报错了 System.out.println(student instanceof String); }
}

总结:

System.out.println(X instanceof Y);

能不能编译通过,取决于X与Y之间是否存在直系继承关系

8.3类的类型转换

  • 基本类型转换

    • 高容量转换成低容量:强制类型转换
    • 低容量转换成高容量:自动类型转换
  • 类之间的转化:父类代表高的,子类代表低的
    • 父转子:强制转换
    • 子转父:自动转换

例子:

package li.oop.demo06;

public class Person {

}
package li.oop.demo06;

public class Student extends Person{
public void go(){
System.out.println("go");
}
}
package li.oop;
import li.oop.demo06.Person;
import li.oop.demo06.Student; public class Application {
public static void main(String[] args) { /*类型之间的转换:
1.基本类型转换-->高容量转换成低容量:强制类型转换
低容量转换成高容量:自动类型转换
2.类之间的转化:父类代表高的,子类代表低的
*/ //高 <--- ---- --- 低
Person student = new Student(); //这里只有在子类Student类中才有go()方法,
// 而student对象是Person类型的,因此不能直接调用,需要强制类型转换成子类类型才能使用go()方法
//高 --- ---- --- > 低
((Student) student).go();//go //或者
Person obj = new Student();
Student student1 = (Student) obj;//强制转换
student1.go();//go /*
子类转换成父类可能会丢失自己本来的一些方法
*/
Student student2 = new Student();
student2.go();//go
Person person = student2;//自动转换 低-->高
//这里的 person对象就不能使用原本子类的go()方法了 }
}

总结:

  1. 父类的引用指向子类的对象(子类的引用不能指向父类的对象)

  2. 把子类转换为父类,向上转型(自动转换)

  3. 把父类转换为子类,向下转型(强制转换)

    基本数据类型的强制转换可能会丢失精度,类的强制转换可能会丢失一些方法

  4. 为什么会存在类的类型转换?方便方法的调用,减少重复代码,更简洁

8.4向上转型

  1. 本质:父类的引用指向子类的对象
  2. 语法:父类类型 引用名=new 子类类型();
  3. 特点:编译类型看左边,运行类型看右边。可以调用父类中的所有成员(须遵守访问权限),不能调用子类中特有成员。
  4. 最终运行效果看子类的具体实现,即调用方法时,从子类开始查找方法,然后调用。

父类类型的引用可以调用父类中定义的所有属性和方法,而对于子类中定义而父类中没有的方法,父类引用是无法调用的;

因为在编译阶段,能调用哪些成员,是由编译类型来决定的。

编译时,会从顶级类开始找调用的方法。运行时,会从运行类型开始,向父类查找方法。

8.4向下转型

  1. 语法:子类类型 引用名 =(子类类型)父类引用;
  2. 只能强转父类的引用,不能强转父类的对象
  3. 要求父类的引用必须指向的是当前目标类型的对象
  4. 当向下转型后,可以调用子类类型中的所有成员
//如下 Animal是父类,Cat是子类
//声明的父类animal引用指向子类Cat
//则 animal的编译类型是Animal,运行类型是Cat
Animal animal = new Cat();
//现在我们向下转型
Cat cat=(Cat)animal;//此刻,编译类型是Cat,运行类型还是Cat

Animal animal = new Cat(); -->意为在堆中有一个Cat对象,然后有一个名为animal的对象引用指向了这个Cat对象;

Cat cat=(Cat)animal; -->意为,有一个名为cat的对象引用,指向了animal指向的Cat对象

现在相当于有两个对象引用(animal,cat)指向了堆中的这个Cat对象。

这也是为什么向下转型,要求父类的引用必须指向的是当前目标类型的对象。

//现在,假如Dog也是Animal的子类,那么
Dog dog=(Dog)animal;//正确吗?
//答案是不正确!!
//因为animal是一个对象引用,它指向的是前面所说的Cat对象。向下转型,要求父类的引用必须指向的是当前目标类型的对象。但当前目标类型变成了Dog
//在编译时不会出错,但是运行时会出现类型转换异常!!

8.5动态绑定机制(DynamicBinding)

运行结果如下:

  • 现在我们把子类B的sum方法删除,请问a.sum()运行结果是什么?

由于子类没有了sum方法,在运行时,根据继承机制,会找到父类的sum方法,在父类的sum方法中会调用getI()+10; 那么问题来了,getI()方法子父类都有,会调用子类的还是父类的呢?

答案是子类的。

这就涉及到动态绑定机制:当调用对象方法的时候,在运行时,该方法会和该类型的运行类型绑定。

在例子中,由于a的运行类型是B,因此会到B类中找getI()方法。在子类的getI()方法中,返回i,由于属性是没有动态绑定机制的,因此返回的就是子类的属性i=20;

所以结果其实是20+10=30;

  • 现在我们把子类B的sum1方法也删除了,请问a.sum1()运行结果是什么?

根据之前的分析,一旦调用对象的方法,该方法会和该对象的内存地址/运行类型绑定。调用a.sum1()方法时,由于a的运行类型是B,因此会到B类中找sum1()方法,但是B中没有sum1方法,于是继承机制发挥作用,去找父类A有没有这个方法,发现有,就调用父类的sum1方法,返回的是i+10;由于属性没有动态绑定机制,就在当前类,即A类中拿到i,使用。

所以结果是10+10=20;

动态绑定机制:

  1. 当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定
  2. 当调用对象属性的时候,没有动态绑定机制,哪里声明,哪里使用

9.static关键字详解

9.1静态变量和静态方法

例子1:静态变量尽量使用类名来访问

package li.oop.demo07;

//static
public class Student {
private static int age;//静态的变量
private double score;//非静态的变量 public static void main(String[] args) {
Student s1 = new Student(); //1.静态变量尽量使用类名来访问
//通过类来使用
System.out.println(Student.age);//0
//通过对象来使用
System.out.println(s1.age);//0
System.out.println(s1.score);//0.0 } }

例子2:静态方法

  • 调用非静态方法需要通过实例对象来调用

  • 调用静态方法可以直接通过类调用,如果如果静态方法和main方法在同一个类中,甚至可以直接调用

  • 非静态方法可以去调用静态方法里的所有东西,而静态方法不能调非静态方法

package li.oop.demo07;

//static
public class Student {
private static int age;//静态的变量
private double score;//非静态的变量 public void run(){
System.out.println("run");
}
public static void go(){
System.out.println("go");
} public static void main(String[] args) { //2.静态方法
//调用非静态方法需要通过实例对象来调用
Student s2 = new Student();
s2.run(); //调用静态方法可以直接通过类调用,如果如果静态方法和main方法在同一个类中,甚至可以直接调用
Student.go();
go(); //3.非静态方法可以去调用静态方法里的所有东西,而静态方法不能调非静态方法
//比如在静态方法main()中不能直接调用非静态方法run() }
}

9.2静态代码块

package li.oop.demo07;

public class Person {
{
//代码块(匿名代码块)
} static{
//静态代码块
} }
  • 如上所示,在类中用大括号括起来的一段没有名字的代码块称为匿名代码块。在括号前加上static关键字的代码块称为静态代码块。

  • 匿名代码块没有名字,程序在执行时并不能主动去调用这些模块。在创建对象的时候匿名代码块自动创建,并且在构造器之前

  • 静态代码块是类加载的同时就直接执行,永久只执行一次

例子:匿名代码块、静态代码块、构造方法的加载顺序

package li.oop.demo07;

public class Person {
{
System.out.println("匿名代码块");//代码块(匿名代码块)
} static{
System.out.println("静态代码块");//静态代码块
} public Person() {
System.out.println("构造方法");
} public static void main(String[] args) { System.out.println("==========111");
Person person1 = new Person(); System.out.println("==========222");
Person person2 = new Person(); }
}

加载顺序:

静态代码块>匿名代码块>构造函数

静态代码块在person1实例化前就执行了,静态代码块是在类加载的同时就执行了,并且只执行一次

9.3静态导入包

package li.oop.demo07;

//静态导入包~
import static java.lang.Math.random;
import static java.lang.Math.PI; public class Test {
public static void main(String[] args) {
System.out.println(random());
System.out.println(PI);
}
}

PS:被final修饰的类不能被其他类继承


day11-面向对象02的更多相关文章

  1. Python面向对象02/类的空间问题、类与对象之间的关系、类与类之间的关系

    Python面向对象02/类的空间问题.类与对象之间的关系.类与类之间的关系 目录 Python面向对象02/类的空间问题.类与对象之间的关系.类与类之间的关系 1. 类的空间问题 2. 类与对象之间 ...

  2. # 095 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 03 封装总结 01 封装知识点总结

    095 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...

  3. 094 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 02 static关键字 04 static关键字(续)

    094 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...

  4. 093 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 02 static关键字 03 static关键字(下)

    093 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...

  5. 092 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 02 static关键字 02 static关键字(中)

    092 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...

  6. 091 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 02 static关键字 01 static关键字(上)

    091 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...

  7. 090 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 04 使用包进行类管理(2)——导入包

    090 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...

  8. 089 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 使用包进行类管理(1)——创建包

    089 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...

  9. 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 02 封装的代码实现

    088 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 02 封装的代码实现 本文知识点:Java封装的代码实现 说明:因为时间紧张,本人写博客过程中只 ...

  10. 087 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 01 封装的概念和特点

    087 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 01 封装的概念和特点 本文知识点:封装的概念和特点 说明:因为时间紧张,本人写博客过程中只是对 ...

随机推荐

  1. Linux系统NTP校时的微调模式

    前言: Linux系统有两个时间同步服务:ntpd和chrony,一般较低版本的系统使用ntpd,新版本系统使用chrony. ntpd有两种校时策略slew和step: slew是平滑.缓慢的渐进式 ...

  2. 跑通的第一个ethers.js程序HelloVitalik.js

    简介 ethers.js是一个本地库,可以让你调用接口,用官方写好的轮子来使用一些常用的函数!学习完这个库,你对node.js就有比较深入的了解了,如果你不做项目,就不涉及智能合约的编写,那么写点脚本 ...

  3. Python常见设置

    pip的相关设置 设置镜像 为pip设置国内的镜像源可以提高Python库下载的速度,这里推荐使用清华大学的镜像站,使用如下命令配置: python -m pip install --upgrade ...

  4. Delphi原子操作函数介绍

    一.Delphi的原子操作函数 在System.SyncObjs单元中,有一个TInterlocked的密封类,其十多个类函数(class function)其实都是调用的System单元的原子操作函 ...

  5. burpsuit+adb+逍遥模拟器

    安卓7之后,单纯的将burpsuit的证书导出手动安装到模拟器中已经不行了,app可以只信任指定证书和系统内置的证书,后续用户安装的证书是不生效的,只能想办法装到系统内部 需要将证书通过openssl ...

  6. JS 数组中找到与目标值最接近的数字,记一次工作中关于二分查找的算法优化

    壹 ❀ 引 在最近的工作中,有一个任务是需要修复富文本编辑器字号显示的BUG.大概情况就是,从WPS中复制不同样式的标题.正文到到项目编辑器中,发现没办法设置选中的文本为正文:而且字体字号都显示为默认 ...

  7. NAND flash 扫盲博客

    从SSD角度学习NAND Flash(一)_小小单片机的博客-CSDN博客 从SSD角度学习NAND Flash(二)_ssd和nand 的交互_小小单片机的博客-CSDN博客 从SSD角度学习NAN ...

  8. Linux查看系统版本的方法

    记录几种查看当前Linux系统的版本的方法 一.使用命令:cat /proc/version 查看 linux版本号:Linux version 5.4.0-99-generic (buildd@lg ...

  9. AIR32F103(十二) 搭载 AIR32F103CBT6 的Bluepill核心板

    目录 AIR32F103(一) 合宙AIR32F103CBT6开发板上手报告 AIR32F103(二) Linux环境和LibOpenCM3项目模板 AIR32F103(三) Linux环境基于标准外 ...

  10. STC89C52驱动MAX7219LED点阵级联, 文字滚动效果

    级联下的传值方式 级联下, N个MAX7219相当于组成了一个8*N bit宽度的锁存器, 如果需要对第M个7219进行写入, 需要做M次寻址+写入后拉高CS, 才能到达这个7219. 如果仅仅对这个 ...