Java面向对象编程学习笔记
内存结构与栈区
- 栈用于存放程序运行过程当中所有的局部变量。一个运行的Java程序从开始到结束会有多次方法的调用。
- JVM会为每一个方法的调用在栈中分配一个对应的空间,这个空间称为该方法的栈帧。一个栈帧对应一个正在调用中的方法,栈帧中存储了该方法的参数、局部变量等数据。
- 当某一个方法调用完成后,其对应的栈帧将被清除。
重载的实际意义
- 方法重载的实际意义在于调用者只需要记住一个方法名就可以调用各种不同的版本,来实现各种不同的功能。
this的基本概念
- 若在构造方法中出现了this关键字,则代表当前正在构造的对象。
- 若在成员方法中出现了this关键字,则代表当前正在调用的对象。
- this关键字本质上就是当前类类型的引用变量。
this的使用方式
- 当局部变量名与成员变量名相同时,在方法体中会优先使用局部变量(就近原则),若希望使用成员变量,则需要在成员变量的前面加上this.的前缀,明确要求该变量是成员变量(重中之重)。
- this关键字除了可以通过this.的方式调用成员变量和成员方法外,还可以作为方法的返回值(重点)
在构造方法的第一行可以使用this()的方式来调用本类中的其它构造方法(了解)。
封装的实现流程
- 私有化成员变量,使用private关键字修饰。
- 提供公有的get和set方法,并在方法体中进行合理值的判断。
在构造方法中调用set方法进行合理值的判断。
构造块和静态代码块(熟悉)
- 构造块:在类体中直接使用{}括起来的代码块。
每创建一个对象都会执行一次构造块。 静态代码块:使用static关键字修饰的构造块。 静态代码块随着类加载时执行一次。
单例设计模式的实现流程
- 私有化构造方法,使用private关键字修饰。
声明本类类型的引用指向本类类型的对象,并使用private static关键字共同修饰。 提供公有的get方法负责将对象返回出去,并使用public static关键字共同修饰。
继承的特点
- 子类不能继承父类的构造方法和私有方法,但私有成员变量可以被继承只是不能直接访问。
无论使用何种方式构造子类的对象时都会自动调用父类的无参构造方法,来初始化从父类中继承的成员变量,相当于在构造方法的第一行增加代码super()的效果。 使用继承必须满足逻辑关系:子类 is a 父类,也就是不能滥用继承。 Java语言中只支持单继承不支持多继承,也就是说一个子类只能有一个父类,但一个父类可以有多个子类。
方法重写的原则
- 要求方法名相同、参数列表相同以及返回值类型相同,从Java5开始允许返回子类类型。
- 要求方法的访问权限不能变小,可以相同或者变大。
- 要求方法不能抛出更大的异常(异常机制)。
继承中的构造代码块与静态代码块的执行顺序
- 先执行父类的静态代码块,再执行子类的静态代码块。
- 执行父类的构造块,执行父类的构造方法体。
- 执行子类的构造块,执行子类的构造方法体。
常用的访问修饰符
多态的特点
- 当父类类型的引用指向子类类型的对象时,父类类型的引用可以直接调用父类独有的方法。
- 当父类类型的引用指向子类类型的对象时,父类类型的引用不可以直接调用子类独有的方法。
- 对于父子类都有的非静态方法来说,编译阶段调用父类版本,运行阶段调用子类重写的版本(动态绑定)。
- 对于父子类都有的静态方法来说,编译和运行阶段都调用父类版本。
引用数据类型之间的转换
- 引用数据类型之间的转换方式有两种:自动类型转换 和 强制类型转换。
- 自动类型转换主要指小类型向大类型的转换,也就是子类转为父类,也叫做向上转型。
- 强制类型转换主要指大类型向小类型的转换,也就是父类转为子类,也叫做向下转型或显式类型转换。
- 引用数据类型之间的转换必须发生在父子类之间,否则编译报错。
- 若强转的目标类型并不是该引用真正指向的数据类型时则编译通过,运行阶段发生类型转换异常。
- 为了避免上述错误的发生,应该在强转之前进行判断,格式如下:
if(引用变量 instanceof 数据类型)
判断引用变量指向的对象是否为后面的数据类型
多态的意义
- 多态的实际意义在于屏蔽不同子类的差异性实现通用的编程带来不同的效果。
抽象类和抽象方法的关系
- 抽象类中可以有成员变量、构造方法、成员方法;
- 抽象类中可以没有抽象方法,也可以有抽象方法;
- 拥有抽象方法的类必须是抽象类,因此真正意义上的抽象类应该是具有抽象方法并且使用abstract关键字修饰的类。
抽象类的实际意义
- 抽象类的实际意义不在于创建对象而在于被继承。
- 当一个类继承抽象类后必须重写抽象方法,否则该类也变成抽象类,也就是抽象类对子类具有强制性和规范性,因此叫做模板设计模式。
接口对于JAVA9的新特性
package com.zhf.JavaStudy.orientedObject; public interface InterfaceTest { /*public static final*/ int CNT = 1; // 里面只能是常量 private void show(){} // 从Java9开始允许接口中出现私有方法 }
类和接口之间的关系
抽象类和接口的主要区别
- 定义抽象类的关键字是abstract class,而定义接口的关键字是interface。
- 继承抽象类的关键字是extends,而实现接口的关键字是implements。
- 继承抽象类支持单继承,而实现接口支持多实现。
抽象类中可以有构造方法,而接口中不可以有构造方法。 抽象类中可以有成员变量,而接口中只可以有常量。 抽象类中可以有成员方法,而接口中只可以有抽象方法。 抽象类中增加方法时子类可以不用重写,而接口中增加方法时实现类需要重写(Java8以前的版本)。 从Java8开始增加新特性,接口中允许出现非抽象方法和静态方法,但非抽象方法需要使用default关键字修饰。 从Java9开始增加新特性,接口中允许出现私有方法。
内部类的分类
- 普通内部类 - 直接将一个类的定义放在另外一个类的类体中。
- 静态内部类 - 使用static关键字修饰的内部类,隶属于类层级。
局部内部类 - 直接将一个类的定义放在方法体的内部时。 匿名内部类 - 就是指没有名字的内部类。
普通内部类的使用方式
- 普通内部类和普通类一样可以定义成员变量、成员方法以及构造方法等。
- 普通内部类和普通类一样可以使用final或者abstract关键字修饰。
- 普通内部类还可以使用private或protected关键字进行修饰。
- 普通内部类需要使用外部类对象来创建对象。
- 如果内部类访问外部类中与本类内部同名的成员变量或方法时,需要使用this关键字。
静态内部类的使用方式
- 静态内部类不能直接访问外部类的非静态成员。
- 静态内部类可以直接创建对象。
- 如果静态内部类访问外部类中与本类内同名的成员变量或方法时,需要使用类名.的方式访问
局部内部类的使用方式
- 局部内部类只能在该方法的内部可以使用。
- 局部内部类可以在方法体内部直接创建对象。
- 局部内部类不能使用访问控制符和static关键字修饰符。
- 局部内部类可以使用外部方法的局部变量,但是必须是final的。由局部内部类和局部变量的声明周期不同所致。
匿名内部类的使用方式
- 接口/父类类型 引用变量名 = new 接口/父类类型() { 方法的重写 };
回调模式的概念
- 回调模式是指——如果一个方法的参数是接口类型,则在调用该方法时,需要创建并传递一个实现此接口类型的对象;而该方法在运行时会调用到参数对象中所实现的方法(接口中定义的)。
枚举的定义
- 使用public static final表示的常量描述较为繁琐,使用enum关键字来定义枚举类型取代常量,枚举类型是从Java5开始增加的一种引用数据类型。
- 枚举值就是当前类的类型,也就是指向本类的对象,默认使用public static final关键字共同修饰,因此采用枚举类型.的方式调用。
- 枚举类可以自定义构造方法,但是构造方法的修饰符必须是private,默认也是私有的。
枚举的使用
package com.lagou.task10; /** * 编程实现所有方向的枚举,所有的方向:向上、向下、向左、向右 */ public class Direction { private final String desc; // 用于描述方向字符串的成员变量 // 2.声明本类类型的引用指向本类类型的对象 public static final Direction UP = new Direction("向上"); public static final Direction DOWN = new Direction("向下"); public static final Direction LEFT = new Direction("向左"); public static final Direction RIGHT = new Direction("向右"); // 通过构造方法实现成员变量的初始化,更加灵活 // 1.私有化构造方法,此时该构造方法只能在本类的内部使用 private Direction(String desc) { this.desc = desc; } // 通过公有的get方法可以在本类的外部访问该类成员变量的数值 public String getDesc() { return desc; } } package com.lagou.task10; public class DirectionTest { public static void main(String[] args) { /*// 1.声明Direction类型的引用指向该类型的对象并打印特征 Direction d1 = new Direction("向上"); System.out.println("获取到的字符串是:" + d1.getDesc()); // 向上 Direction d2 = new Direction("向下"); System.out.println("获取到的字符串是:" + d2.getDesc()); // 向下 Direction d3 = new Direction("向左"); System.out.println("获取到的字符串是:" + d3.getDesc()); // 向左 Direction d4 = new Direction("向右"); System.out.println("获取到的字符串是:" + d4.getDesc()); // 向右 System.out.println("-------------------------------------"); Direction d5 = new Direction("向前"); System.out.println("获取到的字符串是:" + d5.getDesc()); // 向前*/ //Direction.UP = 2; Error:类型不匹配 //Direction d2 = null; //Direction.UP = d2; Error: final关键字修饰 Direction d1 = Direction.UP; System.out.println("获取到的方向是:" + d1.getDesc()); // 向上 System.out.println("-------------------------------------"); // 使用一下Java5开始的枚举类型 DirectionEnum de = DirectionEnum.DOWN; System.out.println("获取到的方向是:" + de.getDesc()); // 向下 } }
Enum类的概念和方法
枚举类实现接口的方式
- 枚举类实现接口后需要重写抽象方法,而重写方法的方式有两种:重写一个,或者每个对象都重写。
枚举类实现接口的实现
package com.lagou.task10; public interface DirectionInterface { // 自定义抽象方法 public abstract void show(); } package com.lagou.task10; /** * 编程实现所有方向的枚举,所有的方向:向上、向下、向左、向右 枚举类型要求所有枚举值必须放在枚举类型的最前面 */ public enum DirectionEnum implements DirectionInterface { // 2.声明本类类型的引用指向本类类型的对象 // 匿名内部类的语法格式:接口/父类类型 引用变量名 = new 接口/父类类型() { 方法的重写 }; // public static final Direction UP = new Direction("向上") { 方法的重写 }; UP("向上") { @Override public void show() { System.out.println("贪吃蛇向上移动了一下!"); } }, DOWN("向下") { @Override public void show() { System.out.println("贪吃蛇向下移动了一下!"); } }, LEFT("向左") { @Override public void show() { System.out.println("左移了一下!"); } }, RIGHT("向右") { @Override public void show() { System.out.println("右移了一下!"); } }; private final String desc; // 用于描述方向字符串的成员变量 // 通过构造方法实现成员变量的初始化,更加灵活 // 1.私有化构造方法,此时该构造方法只能在本类的内部使用 private DirectionEnum(String desc) { this.desc = desc; } // 通过公有的get方法可以在本类的外部访问该类成员变量的数值 public String getDesc() { return desc; } // 整个枚举类型只重写一次,所有对象调用同一个 /*@Override public void show() { System.out.println("现在可以实现接口中抽象方法的重写了!"); }*/ }
注解的基本概念
- 注解(Annotation)又叫标注,是从Java5开始增加的一种引用数据类型。
- 注解本质上就是代码中的特殊标记,通过这些标记可以在编译、类加载、以及运行时执行指定的处理。
注解的语法格式
- 访问修饰符 @interface 注解名称 {
注解成员;}
- 自定义注解自动继承java.lang.annotation.Annotation接口。
通过@注解名称的方式可以修饰包、类、 成员方法、成员变量、构造方法、参数、局部变量的声明等。
注解的使用方式
- 注解体中只有成员变量没有成员方法,而注解的成员变量以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。
如果注解只有一个参数成员,建议使用参数名为value,而类型只能是八种基本数据类型、String类型、Class类型、enum类型及Annotation类型
元注解的概念
- 元注解是可以注解到注解上的注解,或者说元注解是一种基本注解,但是它能够应用到其它的注解上面。
元注解主要有 @Retention、@Documented、@Target、@Inherited、@Repeatable。
元注解@Retention
- @Retention 应用到一个注解上用于说明该注解的的生命周期,取值如下:
RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。 RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中,默认方式。 RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。
元注解@Documented
- 使用javadoc工具可以从程序源代码中抽取类、方法、成员等注释形成一个和源代码配套的API帮助文档,而该工具抽取时默认不包括注解内容。
@Documented用于指定被该注解将被javadoc工具提取成文档。 定义为@Documented的注解必须设置Retention值为RUNTIME。
元注解@Target
元注解@Inherited
- @Inherited并不是说注解本身可以继承,而是说如果一个超类被该注解标记过的注解进行注解时,如果子类没有被任何注解应用时,则子类就继承超类的注解。
元注解@Repeatable
- @Repeatable表示自然可重复的含义,从Java8开始增加的新特性。
从Java8开始对元注解@Target的参数类型ElementType枚举值增加了两个: 其中ElementType.TYPE_PARAMETER 表示该注解能写在类型变量的声明语句中,如:泛型。 其中ElementType.TYPE_USE 表示该注解能写在使用类型的任何语句中。
错题集
虽然初始化时可以赋值,但赋值的含义指赋值可以赋值多次
文字游戏。。。
![]()
面试题
封装具有的特性?
- 减少了耦合
- 便于维护和修改
- 可以隐藏信息,一些具体实现代码,安全性
- 对成员变量精准控制
你好
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)