Java 核心知识总结 面向对象
面向对象的特征
面向对象和面向过程的区别
- 面向过程:是分析解决问题的步骤,然后用函数把这些步骤一步一步地实现,然后在使用的时候一一调用则可。性能较高,所以单片机、嵌入式开发等一般采用面向过程开发。
- 面向对象:是把构成问题的事务分解成各个对象,而建立对象的目的也不是为了完成一个个步骤,而是为了描述某个事物在解决整个问题的过程中所发生的行为。面向对象有封装、继承、多态的特性,所以易维护、易复用、易扩展。可以设计出低耦合的系统。 但是性能上来说,比面向过程要低。
面向对象的三大特性
- 封装:封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。面向对象的本质就是将现实世界描绘成一系列完全自治、封闭的对象。我们在类中编写的方法就是对实现细节的一种封装;我们编写一个类就是对数据和数据操作的封装。可以说,封装就是隐藏一切可隐藏的东西,只向外界提供最简单的编程接口。
- 继承:继承是从已有类得到继承信息创建新类的过程。提供继承信息的类被称为父类;得到继承信息的类被称为子类。继承让变化中的软件系统有了一定的延续性。
- 多态:多态性是指允许不同子类型的对象对同一消息作出不同的响应。多态性分为编译时的多态性和运行时的多态性。方法重载实现的是编译时的多态性(也称为前绑定),而方法重写实现的是运行时的多态性(也称为后绑定)。实现运行时多态需要做两件事:1). 方法重写(子类继承父类并重写父类中已有的或抽象的方法);2). 对象造型(用父类型引用引用子类型对象,这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为)。
深拷贝、浅拷贝、引用拷贝
浅拷贝会在堆上创建一个新的对象,如果原对象内部的属性是引用类型,浅拷贝会直接复制内部对象的引用地址,也就是说拷贝对象和原对象共用同一个内部对象。
深拷贝完全复制整个对象,包括这个对象所包含的内部对象。
引用拷贝就是两个不同的引用指向同一个对象。
介绍一下单例模式,并实现代码
单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问该实例。单例模式通常用于需要确保全局只有一个实例的情况,比如数据库连接、配置对象、日志记录器等。
单例模式有两种常见的实现方式:懒汉式和饿汉式。
- 懒汉式是指在首次需要时才创建实例。这种方式在多线程环境下需要特别注意,需要使用同步措施来保证线程安全。
- 饿汉式是在类加载时就创建实例,因此不存在多线程安全问题。但在某些情况下可能会浪费资源,因为无论是否需要都会创建实例。
详细的说明和代码实现:zhuanlan.zhihu.com/p/160842212
类和类的成员
成员变量和局部变量的区别
成员变量是在类体内声明的变量,由 static 分为实例变量和类变量;局部变量是在方法体内、代码块内或形参列表内声明的变量。
它们之间的区别有:
- 声明位置:类中方法外;方法体、代码块、形参列表内
- 内存中的位置:堆;栈
- 生命周期:随对象一起创建而存在,被 GC 回收而消亡;随方法调用一起存在,执行结束而消亡
- 作用域:在本类中直接使用,外部通过“对象.成员变量”或 getter 使用;只能在作用域内使用
- 修饰符:权限修饰符、final、volatile、transient 等;final
- 默认值:有默认值;无默认值
成员方法的内存解析、重载、参数传递机制
成员方法是对事物行为特征的抽象,可以实现函数的重用,Java 中的方法必须定义在类中,不能独立存在。由 static 分为类方法和实例方法。
方法的内存解析:如果没被调用,就在方法区以字节码的形式存储;被调用后进入栈,栈内会开辟一个内存区域存放当前的局部变量;执行结束后会出栈,若有返回值,将返回值返回给调用处,之后结束执行下一条指令。
方法的重载:在同一个类中,同名和不同参数列表的方法构成重载,与返回值无关,调用时会根据参数列表不同来区别。
方法的参数通过值传递,也就是传递“数据值”和“地址值”。
构造器
在 new 一个新对象时会自动调用构造器。默认的构造器是无参的,权限修饰符与类相同。我们可以重写构造器,重写后就不再提供默认构造器。构造器支持重载,只能用权限修饰符修饰。
类的成员变量赋值过程
依次为:默认初始化、显示初始化、代码块初始化、构造器初始化、提供对象的属性和方法赋值。
方法的重写
子类可以重写父类的方法,需要满足:方法的名称、参数列表相同;子类的返回类型不能大于父类;子类的方法权限不能小于父类;子类的抛出异常不能大于父类。
代码块
代码块用于对 Java 类和对象进行初始化,由 static 分为静态代码块非静态代码块。它用于减少初始化的冗余代码。
什么是 JavaBean
JavaBean 是一种符合特定规范的 Java 类,通常用于在 Java 应用程序中封装数据和业务逻辑,以便于在不同的组件之间传递数据。JavaBean 使代码更加模块化、可维护和可重用。
以下是 JavaBean 的一些特点和规范:
无参构造函数: JavaBean 必须具有一个无参的公共构造函数,以便其他组件可以实例化它。
属性: JavaBean 应该通过 private 成员变量和公共的 Getter 和 Setter 方法来定义属性。属性的命名应该遵循一定的规范,例如 getName() 和 setName()。
可序列化: JavaBean 应该实现 java.io.Serializable 接口,以便可以在网络上传输或持久化到磁盘。
在 Java 中传递参数的方式是什么?
方法的定义可能会用到参数,参数在程序语言中分为:
- 实参(Arguments) :用于传递给方法的参数,必须有确定的值。
- 形参(Parameters) :用于定义方法,接收实参,不需要有确定的值。
程序设计语言将实参传递给方法的方式分为两种:
- 值传递:方法接收的是实参值的拷贝,会创建副本。
- 引用传递:方法接收的直接是实参所引用的对象在堆中的地址,不会创建副本,对形参的修改将影响到实参。
很多程序设计语言(比如 C++)提供了两种参数传递的方式,在 Java 中只有值传递:
- 如果参数是基本类型的话,传递的就是基本类型的字面量值的拷贝,会创建副本。
- 如果参数是引用类型,传递的就是实参所引用的对象在堆中地址值的拷贝,同样也会创建副本。
类中的关键字
介绍一下包
包用于划分项目层次,方便管理,同时解决类命名冲突的问题、控制访问权限。通过 package 声明当前文件所属的包,通过 import 导入其它包内的文件。
this 和 super
this 在方法内部使用,表示调用该方法的对象,this 可以调用成员变量、方法和构造器。在当前方法中有变量名与类中的成员变量重名时,使用 this 调用成员变量,这样做增强代码可读性。若本类中没有,则会在父类中查找。
super 用于调用父类中的成员变量、方法和构造器。用于子类和父类中成员变量重名、子类重写父类方法的情况。若父类中没有,则会继续向上查找。事实上应该避免子类和父类成员变量重名的情况。
native 关键字
native 是 Java 编程语言中的一个关键字,用于表示某个方法的实现是由非 Java 代码提供的。使用 native 关键字,可以在 Java 代码中声明一个方法,但方法的实际实现由其他编程语言(通常是 C、C++ 或其他本地语言)提供。
使用 native 关键字声明的方法在 Java 中只有方法的声明,没有具体的实现代码。实现代码需要在本地语言中编写,并且需要通过 Java Native Interface(JNI)来将 Java 代码和本地代码连接起来。
static 关键字
static 关键字用于属性、方法、代码块、内部类,修饰的内容被所有实例共享。它们随着类的加载而加载、优先于对象存在。(在 JDK6 中,)静态变量存在方法区。静态方法可以被继承,但不能被重写,调用时仅看编译时类型。
final 关键字
final 表示类不能被继承、方法不能被继承、属性赋值后不能被修改。
接口和抽象类有什么共同点和区别?
共同点:
- 都不能被实例化。
- 都可以包含抽象方法。
- 都可以有默认实现的方法(Java 8 可以用 default 关键字在接口中定义默认方法)。
区别:
- 接口主要用于对类的行为进行约束,你实现了某个接口就具有了对应的行为。抽象类主要用于代码复用,强调的是所属关系。
- 一个类只能继承一个类,但是可以实现多个接口。
- 接口中的成员变量只能是 public static final 类型的,不能被修改且必须有初始值,而抽象类的成员变量默认 default,可在子类中被重新定义,也可被重新赋值。
内部类
类 A 定义在类 B 里,类 A 被称为内部类,类 B 被称为外部类。类 A 不对外提供服务时最好作为内部类,这样做是为了遵循高内聚、低耦合的开发原则。
内部类被分为成员内部类和局部内部类,成员内部类分为静态和非静态内部类,局部内部类被分为匿名和非匿名内部类。
🔥静态内部类的好处是什么?应用场景有哪些?
静态内部类与非静态内部类之间存在一个最大的区别,我们知道非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围类,但是静态内部类却没有。没有这个引用就意味着:
- 它的创建是不需要依赖外围类的创建。
- 它不能使用任何外围类的非 static 成员变量和方法。
例如,静态内部类实现单例模式:
public class Singleton {
// 声明为 private 避免调用默认构造方法创建对象
private Singleton() {
}
// 声明为 private 表明静态内部该类只能在该 Singleton 类中被访问
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getUniqueInstance() {
return SingletonHolder.INSTANCE;
}
}
当 Singleton 类加载时,静态内部类 SingletonHolder 没有被加载进内存。只有当调用 getUniqueInstance()
方法从而触发 SingletonHolder.INSTANCE
时 SingletonHolder 才会被加载,此时初始化 INSTANCE 实例,并且 JVM 能确保 INSTANCE 只被实例化一次。
这种方式不仅具有延迟初始化的好处,而且由 JVM 提供了对线程安全的支持。
🔥从类加载机制的角度介绍静态内部类是怎么加载的
加载时机:加载外部类的时候是不会加载内部类的,只有当使用内部类的时候才会去加载内部类
加载过程:见类的加载过程
介绍一下枚举类
枚举类(Enum Class)是一种特殊的类类型,在编程中用于定义一组命名的常量集合。在 Java 中,枚举类可以通过关键字 enum 来定义。枚举类中的每个枚举常量都是该类的一个实例,且只能有限的几个实例。
枚举类的特点和用途包括:
- 类型安全: 枚举类提供了类型安全性,即只能使用该枚举类中定义的常量。这可以防止使用无效的值。
- 有限的实例: 枚举类的实例是有限的,不允许创建新的实例。这样可以确保枚举常量的一致性。
- 可读性: 枚举常量使用有意义的名称,增强了代码的可读性和可维护性。
- 可用于 switch 语句: 枚举常量可以用于 switch 语句,使代码更加清晰。
- 自定义属性和方法: 枚举类可以包含属性和方法,以增加更多的功能。
什么是注解?
注解是 Java5 开始引入的新特性,可以看作是一种特殊的注释,主要用于修饰类、方法或变量,提供某些信息供程序在编译或者运行时使用。注解可以被编译器或其它程序读取。常用的注解有 @Override
、@Deprecated
、@SuppressWarnings
。
注解本质是一个继承了Annotation
的特殊接口:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
public interface Override extends Annotation{
}
JDK 提供了很多内置的注解(比如 @Override
、@Deprecated
),同时,我们还可以自定义注解。
注解的解析方法有哪几种?
注解只有被解析之后才会生效,常见的解析方法有两种:
- 编译期直接扫描 :编译器在编译 Java 代码的时候扫描对应的注解并处理,比如某个方法使用
@Override
注解,编译器在编译的时候就会检测当前的方法是否重写了父类对应的方法。 - 运行期通过反射处理 :像框架中自带的注解(比如 Spring 框架的
@Value
、@Component
)都是通过反射来进行处理的。
转载自:https://juejin.cn/post/7377546788020305960