• java之面向对象


    目录

    面向对象与面向过程

    类和对象

    对象

    类和对象的关系

    类和对象的创建案例 

    创建对象流程

    构造方法

    前言

    形式

    案例

    调用对象内存分析

    内存结构

    对象在内存中的储存

    代码分析 

    this

    this调用属性

    this调用构造方法

    static

    概述

    静态变量和实例变量的区别

    static修饰变量

    static修饰方法

    代码块 

    构造代码块与局部代码块

    形式

    构造代码块的特点

    局部代码块特点

    静态代码块

    格式 

    三种代码块的比较

    代码块与方法的执行顺序

    import导包

    包名定义规则

    封装

    概述

    private关键字

    程序设计

    权限修饰符

    封装总结

    继承

    特点

    子类与父类

    方法的重写

    重写的要求

    重载和重写的区别

    重写和重载的意义

    super

    super调用父类的成员

    super调用父类构造函数

    this与super的区别

    final

    概念

    特点

    多态

    概念

    多态特点

    多态的使用

    向上转型和向下转型

    抽象类及抽象方法

    概念

    总结:

    abstract关键字不可以和以下关键字一起使用

    接口

    接口的特点:

    类接口之间的相互关系

    接口与抽象类的区别

    内部类

    分类

    内部类特点

    成员内部类

    测试类 

    private成员内部类代码

    private成员内部类测试类

    静态内部类

    测试

    局部内部类

    测试

    匿名内部类

    面向对象与面向过程

    • 面向过程:做任何事都需要亲力亲为,强调的是过程,考虑怎么做
    • 面向对象:相对于面向过程,我们的身份可以由原来问题的执行者变为指挥者,进而把生活中很多复杂的问题变得简单化,考虑谁来做

    类和对象

    1. Java语言最基本单位就是类,相当于类型。
    2. 类是一类事物抽取共同属性与功能形成的。
    3. 可以理解为模板或者设计图纸。
    4. 类的组成:属性、方法、构造器、代码块、内部类

    注意:

    1. 类在现实世界并不存在,它只是一种对象的数据类型
    2. 一个源文件中可以有多个类,但只能有一个类被public修饰,源文件的名字必须跟public修饰的那个类名保持一致

    对象

    每个对象具有三个特点:对象的属性,对象的功能和对象的标识。

    1. 对象的属性用来描述对象的基本特征——成员变量。
    2. 对象的功能用来描述对象的可以完成的操作——方法。
    3. 对象的标识是指每个对象在内存中都有一个唯一的地址值用于与其他对象进行区分,类似于我们的身份证号——对象名。

    类和对象的关系

    1. 我们先创建类,再通过类创建出对象
    2. 我们可以通过一个类创建出多个对象
    3. 第一次创建对象时会进行类的加载,并且,类的加载只加载一次
    4. 类是抽象的,对象是具体的,类是对对象的抽象

    类和对象的创建案例 

    1. public class Test1 {
    2. public static void main(String[] args) {
    3. //对象的创建
    4. Phone p=new Phone();//对象的标识
    5. System.out.println(p.price);//对象的属性
    6. p.call();//对象的行为
    7. }
    8. }
    9. class Phone{
    10. //2.定义手机类的属性--用成员变量来描述--位置:类里方法外
    11. String brand;//品牌
    12. double price=3;//价格
    13. double size;//尺寸
    14. String color;//颜色
    15. //3.定义手机类的功能--用方法来描述--格式:修饰符 返回值类型 方法名(参数列表){方法体}
    16. public void call(){
    17. System.out.println("正在打电话~");
    18. }
    19. public void message(){
    20. System.out.println("正在发短信!");
    21. }
    22. public void video(){
    23. System.out.println("正在看直播~");
    24. }
    25. }

    注意:new关键字实际上在调用一个方法,这个方法叫做构造方法(构造器) 

    创建对象流程

    Person p = new Person();//短短这行代码发生了很多事情

    1. 把Person.class文件加载进内存方法区
    2. 在堆内存中,开辟空间,存放Person对象
    3. 对成员变量进行默认的初始化
    4. 对成员变量进行显示初始化
    5. 执行构造方法(如果有构造代码块,就先执行构造代码块再执行构造方法)
    6. 堆内存完成
    7. 在栈内存中,开辟空间,存放引用变量p
    8. 把堆内存的地址值赋值给变量p ,p就是一个引用变量,引用了Person对象的地址值

    构造方法

    前言

    • 构造方法是一种特殊的方法,它是一个与类同名且没有返回值类型的方法
    • 构造方法的主要功能就是完成对象创建或者初始化,不是为了创建对象,在调用构造器之前对象已经创建好了,并且属性有默认初始化的值
    • 当类创建对象(实例化)时,就会自动调用构造方法(无参构造)
    • 构造方法与普通方法一样也可以重载(无参/含参/全参)
    • 默认会创 ,但是,如果自定义了含参构造,默认的无参构造会被覆盖,需要手动添加

    形式

    方法名与类同名,且没有返回值类型,参数列表可以含参也可以不含参

    1. 方法修饰符 方法名(参数列表){//注意方法名与类名相同
    2. 方法体;
    3. }

    案例

    1. public class Test1 {
    2. public static void main(String[] args) {
    3. //对象的创建
    4. Phone p=new Phone("三星",88,22,"绿色");
    5. System.out.println(p.color);//绿色
    6. }
    7. }
    8. class Phone{
    9. //全参构造
    10. public Phone(String brand, double price, double size, String color) {
    11. this.brand = brand;
    12. this.price = price;
    13. this.size = size;
    14. this.color = color;
    15. }
    16. //含参构造
    17. public Phone(double price, double size) {
    18. this.price = price;
    19. this.size = size;
    20. }
    21. //无参构造
    22. public Phone() {
    23. }
    24. //2.定义手机类的属性--用成员变量来描述--位置:类里方法外
    25. String brand;//品牌
    26. double price;//价格
    27. double size;//尺寸
    28. String color;//颜色
    29. }

    调用对象内存分析

    内存结构

    • 栈区:存放栈帧,一般方法的调用在栈帧中进行,局部变量也存在栈帧中
    • 堆区:存放对象的实例
    • 方法区:存放类的字节码信息,静态变量以及常量等

    对象在内存中的储存

    Java把内存分成5大区域,我们重点关注栈和堆。

    • 一般来讲局部变量存在栈中,方法执行完毕内存就被释放
    • 对象(new出来的东西)存在堆中,对象不再被使用时,内存才会被释放
    • 每个堆内存的元素都有地址值
    • 对象中的属性都是成员变量,是有默认值的

    代码分析 

    1. public class Person{
    2. int id;
    3. int age;
    4. public static void main(String[] args) {
    5. Person person = new Person();
    6. }
    7. }

    理解:首先进入main方法,在栈区为main方法分配栈帧为main栈帧,加载Person类的字节码信息Person.class到方法区然后以其为模板在堆内创建Person对象并为其分配一个地址p,并且p指向Person.class说明是以此为模板创建的对象,创建对象同时并完成值得初始化,之后调用构造器方法在栈帧内虚晃一枪,然后在main栈帧中开辟空间存放Person对象的地址值命名为person,将person压入栈底,之后就可以通过person来访问Person对象了

    this

    概念:this代表本类对象的一个引用对象(本类对象的东西)

    this调用属性

    this.属性名=属性值;

    1. public class Person{
    2. int id=2;
    3. public void eat(){
    4. System.out.println("吃饭饭");
    5. }
    6. @Test
    7. public void test1(){
    8. int id=8;
    9. System.out.println(id);//8
    10. System.out.println(this.id);//2
    11. eat();
    12. }
    13. }

    注意:

    • this用来修饰属性
    • 当属性名字和形参发生重名的时候,或者属性名字和局部变量重名的时候,都会发生就近原则;所以如果我们想要指定成员变量的话就要在属性前面加this.修饰
    • 当成员变量如果不发生重名问题的话this也可以省略不写
    • 如果this调用方法的话this可以省略不写

    this调用构造方法

    语法:this();

    注意:

    • 同一个类中的构造器也可以相互用this调用
    • this修饰构造器必须放在第一行
    • this调用构造器不能出现在方法内部
    1. public class Test1 {
    2. public static void main(String[] args) {
    3. //3.1触发无参构造创建本类对象
    4. Dog d1 = new Dog();
    5. //3.2触发含参构造创建本类对象
    6. //Dog d2 = new Dog("旺财");
    7. }
    8. }
    9. class Dog{
    10. public Dog(){
    11. //无参构造
    12. this("小旺旺");
    13. System.out.println("无参构造");
    14. }
    15. //含参构造
    16. public Dog(String s){
    17. //不能两个this回调,否则会出现死循环
    18. //this();
    19. System.out.println("含参构造"+s);
    20. }
    21. }
    22. //含参构造小旺旺
    23. //无参构造

    static

    概述

    static是java中的一个关键字用于修饰成员变量和成员方法等

    • static可以修饰:属性、方法、代码块、内部类(不可以修饰构造器)
    • 被static修饰的资源称为静态资源(也称类资源),存在方法区
    • 静态资源随着类的加载而加载,最先加载,优先于对象进行加载
    • 静态资源可以通过类名直接调用,也被称作类资源
    • 静态资源被全局所有对象共享,值只有一份
    • 静态资源只能调用静态资源,因为其先于对象加载
    • 静态区域内不允许使用this与super关键字,因为有static时可能还没有对象
    • 对象可以调用静态资源,并且通过对象可以更改static修饰的共享资源

    静态变量和实例变量的区别

    • 静态变量属于类的,实例变量属于对象的
    • 静态变量前面加static,实例变量不加

    static修饰变量

    1. public class Test {
    2. int id;
    3. static int sid;
    4. public static void main(String[] args) {
    5. Test t1 = new Test();
    6. t1.id=10;
    7. t1.sid=10;
    8. Test t2 = new Test();
    9. t2.id=20;
    10. t2.sid=20;//此时该类的变量已经为20
    11. System.out.println(t1.id);//10
    12. System.out.println(t2.id);//20
    13. System.out.println(t1.sid);//20
    14. System.out.println(t2.sid);//20
    15. //原理:static修饰的变量被全局共享
    16. Test.sid=80;
    17. System.out.println(Test.sid);//被static修饰的变量可以通过类名直接调用
    18. }
    19. }

    static修饰方法

    1. public class Demo {
    2. int id=2;
    3. static int sid=5;
    4. //普通方法访问静态非静态均可
    5. public void m1(){
    6. System.out.println(id);
    7. System.out.println(sid);
    8. System.out.println("方法1");
    9. }
    10. //静态方法只可访问静态变量
    11. static public void m2(){
    12. //System.out.println(id);//报错
    13. System.out.println(sid);
    14. System.out.println("方法2");
    15. }
    16. public static void main(String[] args) {
    17. Demo.m2();
    18. }
    19. }

    代码块 

    代码块分类:局部代码块、构造代码块、静态代码块、同步代码块

    构造代码块与局部代码块

    形式

    语法:{ 代码… }

    构造代码块的特点

    1. 位置: 在类的内部,在方法的外部
    2. 作用: 用于抽取构造方法中的共性代码
    3. 执行时机: 每次调用构造方法前都会调用构造代码块
    4. 注意事项: 构造代码块优先于构造方法加载

    局部代码块特点

    1. 位置: 在方法里面的代码块
    2. 作用: 通常用于控制变量的作用范围,出了花括号就失效
    3. 注意事项: 变量的作用范围越小越好,成员变量会存在线程安全的问题

    静态代码块

    格式 

    语法:static{}

    静态资源随着类的加载而加载,并且只被加载一次,一般用于项目的初始化
    特点: 被static修饰,位置在类里方法外

    三种代码块的比较

    1. 静态代码块:在类加载时就加载,并且只被加载一次,一般用于项目的初始化
    2. 构造代码块:在创建对象时会自动调用,每次创建对象都会被调用,提取构造共性
    3. 局部代码块:方法里的代码块,限制局部变量的范围

    代码块与方法的执行顺序

    静态代码块 --> 静态方法-->构造代码块 --> 构造方法 --> 局部代码块 

    注意:静态代码块与静态变量都存在,则会按照顺序合二为一执行,因为两者同级别 

    import导包

    导包的作用:解决重名问题(实际上包对应的就是盘符上的目录)

    创建包:idea中new Package

    包名定义规则

    • 名字全部小写,中间用.隔开
    • 名字一般都是公司域名倒写,一般会加模块名
    • 不能使用系统关键字(nul,con,com1——com9……)
    • 包声明的位置一般都在非注释型代码的第一行
    • 使用外面包中的具体类需要导包
    • 同一个包下的类要想使用不需要导包,可以直接使用
    • 导包时内部的*代表该包下的第一层所有类均导入
    • 包中的.分割着多个目录
    • 在静态导入后,用一个类种有相同方法的时候会优先走自己的方法

    包声明:package 包名;(供外界使用,一定要加)

    导包:import 包名.类名;(供自己使用)

    1. import static java.lang.Math.random;
    2. public class Pkg {
    3. public static void main(String[] args) {
    4. System.out.println(random());//1000
    5. }
    6. public static int random(){
    7. return 1000;
    8. }
    9. }

    封装

    概述

    含义:将某些东西进行隐藏,然后提供相应的方式进行获取

    好处:

    1. 提高安全性
    2. 提高重用性

    private关键字

    是一个权限修饰符 ,可以用来修饰成员变量和成员方法.被私有化的成员只能在本类中访问

    如何封装:我们可以使用private等关键字来封装成员变量与方法

    如何访问封装的成员变量:通过get/set方法

    1. public class Test1 {
    2. public static void main(String[] args) {
    3. User u = new User();
    4. //修改对象的属性值,可以直接修改
    5. u.name = "李逵";
    6. //可以直接访问
    7. System.out.println(u.name);
    8. //封装属性的修改与访问
    9. u.setSex("男");
    10. System.out.println(u.getSex());
    11. }
    12. }
    13. class User{
    14. String name;
    15. //封装属性--通过private关键字封装属性
    16. private String sex;
    17. public String getSex() {
    18. return sex;
    19. }
    20. public void setSex(String sex) {
    21. if("男".equals(sex)||"女".equals(sex)){
    22. this.sex = sex;
    23. }else{
    24. this.sex="男";
    25. }
    26. }
    27. public User() {
    28. }
    29. public User(String name, String sex) {
    30. this.name = name;
    31. //调用构造器时对设置的性别进行限制
    32. setSex(sex);
    33. }
    34. }

    程序设计

    • 高内聚:类的内部数据操作自己来完成,不允许外部的干涉(相关性很强)
    • 低耦合:仅对外部暴露少量的方法用于使用,将该隐藏的隐藏起来,将该暴露的暴露出来

    权限修饰符

    含义:用来控制一个类,或者类中的成员的访问范围。

    作用:实现封装

    在这里插入图片描述

    注意:

    • 在同一模块内,如果不在同一模块内想使用另一模块功能则需要导入jar包并且将另一模块用public修饰符修饰 
    • protected修饰符如果子类和父类不在同一个包,父类属性被protected修饰,那么子类也是可以访问该父类属性
    • 类的权限修饰符两种:缺省、public

    封装总结

    1. 将属性私有化,被private等权限修饰符修饰,一旦加入权限修饰符,其他人就不可以随意的获取这个属性
    2. 提供public修饰方法让别人来访问/使用
    3. 即使外界可以通过方法来访问属性了,但也不能随意访问,因为在它访问属性的方法中我们可以加入限制条件
    4. 外部访问封装属性的方法有个约定,修改属性用setter方法,获取属性用getter方法

    继承

    含义:继承是从已有的类中派生出新的类,新类能吸收已有类的数据属性和行为,并扩展新的能力.

    理解:将多个类的共同部分向上抽取形成一个大类,这个类就是被继承的父类,继承是对类的抽象

    特点

    1. 使用extends关键字来表示继承关系
    2. 相当于子类把父类的功能复制了一份
    3. Java只支持单继承,一个子类只能有一个父类,但一个父类可以有多个子类
    4. 继承可以传递(爷爷/儿子/孙子这样的关系)
    5. 继承多用于功能的修改,子类可以在拥有父类功能的同时,进行功能拓展

    子类与父类

    • 子类继承父类可以调用父类的非私有属性及方法,若子类属性和方法与父类一样则子类调用子类的属性及方法
    • 父类的私有成员由于私有限制访问在子类中不可见,所以子类不能使用父类的私有资源,但是此私有属性已经继承过来了
    • 类的加载顺序:先父类后子类
    • 所有的类都直接或间接继承自Object类
    • 先有父类,再有子类=>继承、先有子类,再抽取父类=>泛化 

    格式:子类 extends 父类

    1. public class Test1 {
    2. public static void main(String[] args) {
    3. Animal a = new Animal();
    4. Cat c = new Cat();
    5. MiaoMiao m = new MiaoMiao();
    6. a.eat();//爷爷类使用自己的方法
    7. c.eat();//爸爸类可以使用从爷爷类中继承过来的方法
    8. m.eat();//孙子类也可以使用从爷爷类中继承过来的方法
    9. }
    10. }
    11. class Animal{
    12. public void eat(){
    13. System.out.println("小动物Animal吃啥都行~");
    14. }
    15. }
    16. class Cat extends Animal{
    17. int a = 10;//普通属性
    18. private int b = 100;//私有属性
    19. }
    20. class MiaoMiao extends Cat{
    21. public void studyJava(){
    22. System.out.println("正在学Java");
    23. System.out.println(a);
    24. }
    25. }

    方法的重写

    定义:发生在子类和父类当中,当子类对父类提供的方法不满意的时候,要对父类的方法进行重写

    1. 继承以后,子类就拥有了父类的功能
    2. 在子类中,可以添加子类特有的功能,也可以修改父类的原有功能
    3. 子类中方法的签名与父类完全一样时,会发生覆盖/复写的现象
    4. 父类的私有方法不能被重写,因为不可见

    重写的要求

    两同:

    1. 方法名
    2. 参数列表 

    两小:

    1. 子类返回值类型小于等于父类的返回值类型(注意此处说的是继承关系,不是值大小)
    2. 子类抛出异常小于等于父类方法抛出异常

    注意:父类的方法的返回值类型若为基本数据类型则子类方法的返回值类型也为基本数据类型,父类方法的返回值类型为引用类型则子类方法的返回值类型为父类方法返回值类型的本类或子类

    一大:子类方法的修饰符权限要大于等于父类被重写方法的修饰符权限

    1. public class Test1 {
    2. public static void main(String[] args) {
    3. Cat cat = new Cat();
    4. cat.eat();//猫cat吃啥都行~
    5. cat.run();//动物喜欢爬树
    6. }
    7. }
    8. class Animal{
    9. public void eat(){
    10. System.out.println("小动物Animal吃啥都行~");
    11. }
    12. public void run(){
    13. System.out.println("动物喜欢爬树");
    14. }
    15. }
    16. class Cat extends Animal{
    17. @Override//重写注解标识
    18. public void eat(){
    19. System.out.println("猫cat吃啥都行~");
    20. super.eat();
    21. }
    22. }

    重载和重写的区别

    重写和重载的意义

    • 重载的意义:是为了外界调用方法时方便,不管传入什么样的参数,都可以匹配到对应的同名方法
    • 重写的意义:在不修改源码的情况下,进行功能的修改与拓展(OCP原则:面向修改关闭,面向拓展开放)

    super

    概念:父类对象的一个引用对象

    理解:在子类方法中,可以通过super.属性/super.方法的方式显式的去调用父类提供的属性以及方法,通常情况下super.可以省略不写

    super调用父类的成员

    语法:super.属性名=属性值;

    1. import org.junit.Test;
    2. public class Girl extends Person{
    3. String name="lala";
    4. public void getAge(){
    5. System.out.println(age);//这里的super.省略了(因为子类里没有)
    6. }
    7. @Test
    8. public void test1(){
    9. System.out.println(name);//lala
    10. System.out.println(super.name);//父类名字lili
    11. getAge();
    12. super.getAge();
    13. }
    14. }
    15. class Person{
    16. String name="lili";
    17. int age=8;
    18. public void getAge(){
    19. System.out.println("父类getAge");
    20. }
    21. }

    super调用父类构造函数

    调用的是父类的无参构造:super();

    调用父类的含参构造:super(参数列表);

    1. public class Girl extends Person{
    2. String name;
    3. public Girl(String name,int age) {
    4. super(age);
    5. this.name = name;
    6. }
    7. }
    8. class Person{
    9. int age;
    10. public Person(int age) {
    11. this.age = age;
    12. }
    13. }
    14. class Test2{
    15. public static void main(String[] args) {
    16. Girl lili = new Girl("lili", 9);
    17. System.out.println(lili.name+lili.age);
    18. }
    19. }

    注意:

    • 当父类的成员变量与子类的变量同名时,使用super指定父类的成员变量
    • 使用super可以在子类构造方法的第一行调用父类构造方法的功能
    • 在构造方法里,出现的调用位置必须是第一行,每个子类的构造函数(无参/含参/全参)第一行中都默认有super();
    • 若第一行已经显示了父类的其他构造器,那么他的第一行就没有默认分配的super();了
    • 在构造器中,super调用父类构造器和this调用子类构造器只能存在一个,两者不能共存

    this与super的区别

    在这里插入图片描述

    注意:如果子类重写了父类的方法以后,可以使用super.方法名(参数列表)来调用 

    final

    语法:final 属性名=属性值;

    概念

    1. 是java提供的一个关键字
    2. final是最终的意思
    3. final可以修饰类,方法,字段(属性)

    特点

    1. 被final修饰的类,不能被继承
    2. 被final修饰的方法,不能被重写
    3. 被final修饰的基本数据类型,那么该变量为常量,值不能被修改;final修饰引用数据类型,那么该引用类型的地址不能被修改

    多态

    概念

    含义:指同一个实体同时具有多种形式,即同一个对象,在不同时刻,代表的对象不一样,指的是对象的多种形态。

    理解:父类当做方法的形参,然后传入具体的子类对象,调用同一个方法,根据传入子类的不同展现出方法的效果也不同,构成了多态

    注意:多态与属性无关,多态指的是方法的多态,而不是属性的多态

    多态的好处:为了提高代码的扩展性,符合面向对象的设计原则:开闭原则(扩展是开放的,修改是关闭的)

    多态特点

    1. 多态的前提:类的继承、子类方法的重写
    2. 父类引用指向子类对象(Animal a = new Cat())
    3. 多态中,编译时看左边,运行时看右边

    多态的使用

    1. 成员变量: 使用的是父类的
    2. 成员方法: 由于存在重写现象,所以使用的是子类的

    向上转型和向下转型

    • 向上转型:多态(父类引用指向子类对象)
    • 向下转型:强制转换
    1. public class Test1 {
    2. public static void main(String[] args) {
    3. Animal2 a=new Dog2();//向上转型
    4. a.eat();//小狗爱吃肉包子
    5. System.out.println(a.sum);//10
    6. System.out.println(((Dog2) a).sum);//20——向下转型
    7. }
    8. }
    9. class Animal2{
    10. int sum = 10;
    11. public void eat(){
    12. System.out.println("吃啥都行~");
    13. }
    14. public static void play(){
    15. System.out.println("玩啥都行~");
    16. }
    17. }
    18. class Dog2 extends Animal2{
    19. int sum = 20;
    20. @Override
    21. public void eat(){
    22. System.out.println("小狗爱吃肉包子");
    23. }
    24. //静态方法属于类方法,不存在重写
    25. public static void play(){
    26. System.out.println("小狗喜欢玩皮球~");
    27. }
    28. }

    抽象类及抽象方法

    概念

    Java中可以定义被abstract关键字修饰的类,被abstract关键字修饰的类叫做抽象类;被abstract关键字修饰的方法,这种方法只有声明,没有方法体,叫做抽象方法.​​​​​

    抽象方法格式:权限修饰符 abstract 返回值类型 方法名(参数列表); 

    总结:

    1. abstract 可以修饰方法或者类
    2. 被abstarct修饰的类叫做抽象类,被abstract修饰的方法叫做抽象方法
    3. 如果类中有抽象方法,那么该类必须定义为一个抽象类
    4. 抽象类可以不含抽象方法
    5. 子类继承了抽象类以后,要么还是一个抽象类,要么就把父类的所有抽象方法都重写
    6. 抽象类不可以被实例化,但是有构造方法
    7. 抽象方法没有方法体
    8. 抽象类中的方法实现交给子类来完成
    9. 抽象类构造方法存在的意义:为了子类创建对象使用super()
    1. public class Test1 {
    2. public static void main(String[] args) {
    3. Animal a = new Pig();
    4. a.eat();//调用抽象父类的普通方法
    5. a.fly();//调用抽象父类的抽象方法
    6. }
    7. }
    8. //抽象类
    9. abstract class Animal{
    10. public Animal() {
    11. System.out.println("我是父类构造");
    12. }
    13. //3.创建普通方法
    14. public void eat(){
    15. System.out.println("吃啥都行~");
    16. }
    17. public void play(){
    18. System.out.println("玩啥都行~");
    19. }
    20. //抽象方法
    21. public abstract void fly();
    22. public abstract void fly2();
    23. }
    24. class Pig extends Animal{
    25. @Override//注解,标识这是一个重写的方法
    26. public void fly() {
    27. System.out.println("我爸的债我终于还清了,我家的猪终于飞起来了~");
    28. }
    29. @Override
    30. public void fly2() {
    31. System.out.println("抽象父类中的所有抽象方法都需要被实现");
    32. }
    33. }
    34. //我是父类构造
    35. //吃啥都行~
    36. //我爸的债我终于还清了,我家的猪终于飞起来了~

    abstract关键字不可以和以下关键字一起使用

    • private:被私有化后,子类无法重写,与abstract相违背。
    • static:静态优先于对象存在,存在加载顺序问题。
    • final:被final修饰后,无法重写,与abstract相违背。

    接口

    含义:接口( Interface )在Java中也是一种抽象类型,接口中的内容是抽象形成的需要实现的功能,接口更像是一种规则和一套标准.

    接口格式:interface 接口名{……代码……}

    接口的特点:

    1. 通过interface关键字来定义接口
    2. 实现类如果想要用接口的功能,要和接口建立实现关系,通过关键字implements实现
    3. 如果实现类与接口建立关系以后,可以选择不实现接口中的抽象方法,而是把自己变成一个抽象子类
    4. 接口里所有的修饰符都是public,可以省略不写
    5. 接口里的变量都是静态常量,所以你定义一个变量没有写修饰符时,默认会加上public static final
    6. 接口里有抽象方法、静态方法、默认方法,只有抽象方法没方法体,抽象方法如果没有写修饰符时,默认会加上public abstract,默认方法若被重写应去掉default
    7. 实现类中调用接口的默认方法:接口名.super.默认方法名();/方法名();
    8. 可以把接口理解成一个特殊的抽象类(但接口不是类!!!)
    9. 接口和类之间可以多实现,接口与接口之间可以多继承
    10. 接口是对外暴露的规则,是一套开发规范
    11. 接口里面没有构造方法,不能创建对象,但是支持多态
    12. 接口里的静态方法只能通过接口名直接调用,而继承关系的静态方法不仅可以通过类的对象调用,也可以通过子类类名来调用。
    13. 继承是is a的关系,实现是has a的关系(*)(原因:因为类相对于接口那么就是一个具体的东西,接口相对于类是一个抽象的东西)
    1. public class Test4 {
    2. public static void main(String[] args) {
    3. UserInter u = new UserInterImpl();
    4. u.eat();
    5. u.play();
    6. System.out.println(u.age);
    7. UserInter.fly();
    8. }
    9. }
    10. interface UserInter{
    11. public static final int age = 20;
    12. public abstract void eat();
    13. void play();
    14. //静态方法
    15. static void fly(){
    16. System.out.println("一飞冲天");
    17. }
    18. //默认方法
    19. default void run(){
    20. System.out.println("一路顺风");
    21. }
    22. }
    23. //3.创建接口的实现类
    24. class UserInterImpl implements UserInter{
    25. @Override
    26. public void eat() {
    27. System.out.println("实现接口中的抽象方法1");
    28. }
    29. @Override
    30. public void play() {
    31. //实现类中调用接口的默认方法
    32. UserInter.super.run();
    33. System.out.println("实现接口中的抽象方法2");
    34. }
    35. }
    36. //实现接口中的抽象方法1
    37. //实现接口中的抽象方法2
    38. //20
    39. //一飞冲天

    类接口之间的相互关系

    • 类与类的关系:继承关系,只支持单继承
    • 类和接口的关系:实现关系.可以单实现,也可以多实现——class A implements B,C{}
    • 接口与接口的关系:是继承关系,可以单继承,也可以多继承——interface A extends B,C{}

    接口与抽象类的区别

    • 接口是一种用interface定义的类型,抽象类是一种用class定义的类型
    • 接口中的方法有抽象方法,还有默认方法与静态方法,抽象类中没有默认方法,但有普通方法
    • 接口中的都是静态常量,抽象类中可以写普通的成员变量
    • 接口没有构造方法,不可实例化,抽象类有构造方法,但是也不可以实例化
    • 接口是先天设计的结果,抽象是后天重构的结果
    • 接口可以多继承,抽象类只能单继承

    内部类

    定义:内部类就是在一个类的内部再定义一个类,比如A类中定义一个B类,那么B类相对于A类来说就是一个内部类

    分类

    • 成员内部类
    • 静态内部类
    • 局部内部类
    • 匿名内部类

    内部类特点

    • 内部类可以直接访问外部类的成员,包括私有成员
    • 外部类想要访问内部类成员必须建立内部类对象 

    成员内部类

    定义:在成员位置的内部类是成员内部类

    1. public class Outer {
    2. private int id=10;
    3. public void out(){
    4. System.out.println("我是外部类方法");
    5. }
    6. class Inner{
    7. public void in(){
    8. System.out.println("我是内部类方法");
    9. }
    10. //内部可以获得外部类的私有属性
    11. public int getId() {
    12. return id;
    13. }
    14. //内部可以获得外部类的私有以及非私有方法
    15. public void get(){
    16. out();
    17. }
    18. }
    19. }

    测试类 

    1. public class Test {
    2. public static void main(String[] args) {
    3. Outer outer = new Outer();
    4. //通过外部类来实例化内部类
    5. Outer.Inner inner = outer.new Inner();
    6. //获得内部类方法
    7. inner.in();
    8. //获得外部类私有属性
    9. System.out.println(inner.getId());
    10. //获得外部类方法
    11. inner.get();
    12. }
    13. }

    注意:成员内部类被Private修饰以后,无法被外界直接创建创建对象使用,所以可以创建外部类对象,通过外部类对象间接访问内部类的资源(private权限修饰符生效的为本类,这个本类就是指本外部类)

    private成员内部类代码

    1. public class Outer {
    2. private int id=10;
    3. public void out(){
    4. System.out.println("我是外部类方法");
    5. }
    6. //外部类使用内部类资源
    7. public void find(){
    8. //外部类无法直接获取内部类的属性及方法,如果要获取需要创建内部类对象
    9. //创建内部类对象
    10. Inner inner = new Inner();
    11. //获得内部类方法
    12. inner.in();
    13. //获得内部类属性
    14. System.out.println(inner.sum);
    15. }
    16. private class Inner{
    17. int id=20;
    18. private int sum=100;
    19. public void in(){
    20. System.out.println("我是内部类方法");
    21. }
    22. //内部可以获得外部类的私有属性
    23. public int getId() {
    24. System.out.println(id);
    25. //成员变量和外部类重名时获取外部类成员
    26. return Outer.this.id;
    27. }
    28. //内部可以获得外部类的私有以及非私有方法
    29. public void get(){
    30. out();
    31. }
    32. }
    33. }

    private成员内部类测试类

    1. public class Test {
    2. public static void main(String[] args) {
    3. Outer outer = new Outer();
    4. outer.find();
    5. }
    6. }

    静态内部类

    1. public class Outer {
    2. private int id=10;
    3. public void out(){
    4. System.out.println("我是外部类方法");
    5. }
    6. public static class Inner{
    7. public int sum=100;
    8. public static void in(){
    9. System.out.println("我是内部类方法");
    10. }
    11. }
    12. }

    测试

    1. public class Test {
    2. public static void main(String[] args) {
    3. //创建静态内部类对象
    4. Outer.Inner inner = new Outer.Inner();
    5. //访问静态内部类的属性
    6. System.out.println(inner.sum);
    7. //访问静态内部类里的静态资源
    8. Outer.Inner.in();
    9. }
    10. }

    局部内部类

    定义:在局部位置的内部类是局部内部类

    1. public class Outer {
    2. private int id=10;
    3. public void out(){
    4. final int num=100;
    5. System.out.println("我是外部类方法");
    6. class Inner{
    7. private int sum=100;
    8. private void in(){
    9. System.out.println(num);//在局部内部类中访问的变量必须是final修饰的变量
    10. System.out.println("我是内部类方法");
    11. }
    12. }
    13. //使用局部内部类的资源
    14. Inner inner = new Inner();
    15. System.out.println(inner.sum);
    16. inner.in();
    17. }
    18. }

    注意:在局部内部类中访问到的变量必须是final修饰的变量 (原因:局部变量的生命周期与局部内部类对象的生命周期不一致,局部对象若想使用该局部变量,那么必须延长该局部变量的生命周期,伪延长方法:为局部变量加final修饰符将局部变量复制一份,复制品直接作为局部内部类中的数据成员)

    测试

    1. public class Test {
    2. public static void main(String[] args) {
    3. new Outer().out();
    4. }
    5. }

    匿名内部类

    定义:没有具体名字的内部类

    1. public class Outer {
    2. public static void main(String[] args) {
    3. //创建匿名内部类——实现了该接口的实现类,并调用save方法
    4. new UserService(){
    5. @Override
    6. public void save() {
    7. System.out.println("我是save方法");
    8. }
    9. }.save();
    10. //创建匿名内部类——该抽象类的子类
    11. new Aclass(){
    12. @Override
    13. void delete() {
    14. System.out.println("我是delete方法");
    15. }
    16. };
    17. }
    18. }
    19. interface UserService{
    20. void save();
    21. }
    22. abstract class Aclass{
    23. abstract void delete();
    24. }

    注意:匿名内部类属于局部内部类,而且是没有名字的局部内部类,通常和匿名对象一起使用 

  • 相关阅读:
    el-table 对循环产生的空白列赋默认值
    买房需要了解的一些事
    C# - readonly 和 const 关键字
    关于SpringBoot项目中读取不到自建email.yml配置文件内容的问题
    云原生数据库的到来
    Springboot+RabbitMQ+ACK机制(生产方确认(全局、局部)、消费方确认)、知识盲区
    【ArcGIS Pro微课1000例】0020:ArcGIS Pro中河流(曲线)、湖泊(水体色)图例制作案例教程
    自定义事件内容分发
    【Try to Hack】vulhub靶场搭建
    自定义字符串排序(791.leetcode,string)-------------------c++实现
  • 原文地址:https://blog.csdn.net/m0_60027772/article/details/126058775