clone()
方法:
clone()
方法用于创建并返回当前对象的一个副本(克隆)。要使用该方法,类必须实现 Cloneable
接口,并重写 clone()
方法。Cloneable
接口是一个标记接口,它没有任何方法,只是用于标识该类可以被克隆。clone()
方法时,通常需要调用 super.clone()
方法来获得对象的浅拷贝副本,然后根据需要进行深拷贝。clone()
方法执行的是浅拷贝,即复制对象的字段值,但不复制引用对象本身。如果需要实现深拷贝,需要在 clone()
方法中对引用对象进行单独的拷贝操作。finalize()
方法:
finalize()
方法是垃圾回收器在销毁对象之前调用的方法。finalize()
方法进行一些清理操作。finalize()
方法为空,但可以在子类中重写该方法,以定义对象在被销毁之前的清理行为,如关闭文件、释放资源等。finalize()
方法的及时执行,因此不应该过于依赖该方法来释放资源,而应该使用显式的资源释放方法(如 close()
)来确保资源的及时释放。toString()
方法:
toString()
方法返回表示对象的字符串表示。@
符号和对象的哈希码组成的字符串。toString()
方法,以返回更有意义的对象描述。通常,重写的 toString()
方法会返回对象的属性值以及其他有用信息的字符串表示。equals()
方法:
equals()
方法用于比较两个对象是否相等。equals()
方法比较的是对象的引用是否相等,即两个对象是否指向同一个内存地址。equals()
方法,可以改变相等的定义。通常,重写的 equals()
方法会比较对象的属性值,判断它们是否相等。equals()
方法时,通常还需要重写 hashCode()
方法,以保证在使用基于哈希的集合类(如 HashMap
、HashSet
)时能够正确地比较和存储对象。
equals()
方法原则x.equals(y)
返回true
,那么y.equals(x)
也应该返回true
。x.equals(x)
必须返回true
。x.equals(y)
返回true
,且y.equals(z)
返回true
,那么z.equals(x)
也应该返回true
。x.equals(y)
返回true
,只要x
和y
的内容不变,无论重复多少次调用x.equals(y)
,都应该返回true
。x.equals(null)
应该始终返回false
。x.equals(obj)
中,如果obj
的类型与x
不同,应该始终返回false
。==
运算符既可以用于比较基本类型的值,也可以用于比较引用类型的内存地址。对于基本类型,它比较的是值是否相等;对于引用类型,它比较的是引用是否指向同一个对象(即内存地址是否相等)。equals()
方法是 java.lang.Object
类中定义的方法,如果没有在自定义类中重写该方法,那么默认的行为就是使用 ==
运算符进行引用相等性的比较。然而,许多类(如 String
)会重写 equals()
方法,以便根据对象的值来确定相等性,而不仅仅是引用的比较。这可能导致一些误解,使人误认为 equals()
方法在所有情况下都比较值。equals()
方法,并根据类的属性来确定相等性。这样可以根据具体需求定义对象相等的条件区别点 | == |
equals |
---|---|---|
定义 | == 是一个操作符,用于比较两个变量的值是否相等 |
equals 是一个方法,用于比较两个对象的内容是否相等 |
适用类型 | 适用于基本数据类型和对象引用。 | 适用于对象 |
比较方式 | 比较操作数的值 | 比较操作数所引用的对象的内容 |
返回值 | true 如果两个操作数的值相等,否则返回 false |
true 如果两个对象的内容相等,否则返回 false |
重载 | == 不能被重载 |
equals 方法可以被重载 |
需要根据具体情况选择使用哪种比较方式。
==
。equals()
,除非只想检查是否引用同一个对象,然后才使用 ==
。主要差别在于:
==
只检查值。equals()
检查值和类型。所以总的来说:
==
时要小心底层对象可能改变(如 String
包装类Integer、
Double等)。equals()
来判断对象的相等性。Java中的’ native '关键字用于表示方法是本机函数,这意味着该方法是用Java以外的语言实现的,例如C/ c++,并被编译成Java调用的DLL(动态链接库)。
下面是一些需要理解的关于原生方法的要点:
本机方法具有用不同的编程语言(通常是C或c++)实现的主体。然而,由于本机方法体的源代码不对我们开放,我们无法看到它的实现。
在Java中定义本机方法时,只声明其签名而不提供实现。
为什么使用本机方法?
虽然Java使用起来很方便,但是有些任务在Java中不容易完成,或者性能很关键。在这种情况下,可以使用本机方法,特别是在与低级操作系统或特定硬件交互时。本机方法提供了一个简洁的接口来执行这些任务,而不必深入研究Java领域之外的复杂细节。
本机方法可以像任何其他Java方法一样被调用者使用
本机方法的存在不会影响调用这些方法的其他类。实际上,调用这些方法的其他类甚至可能不知道它们正在调用本机方法。JVM处理调用本机方法的所有细节。
总之,Java中的本机方法提供了一种方法,可以将用其他语言实现的功能合并到Java程序中,从而实现与低级操作或特定于硬件的任务的有效交互,同时为应用程序的其余部分保持Java语言的便利性和简单性。
设计模式是在大量的实践中总结
和理论化
之后优选的代码结构、编程风格、以及解决问题的思考方式。设计模式免去我们自己再思考和摸索。就像是经典的棋谱,不同的棋局,我们用不同的棋谱。“套路”
经典的设计模式共有23种。每个设计模式均是特定环境下特定问题的处理方法。
简单工厂模式并不是23中经典模式的一种,是其中工厂方法模式的简化版
单例设计模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问该实例。
在单例模式中,类的构造函数是私有的,这样外部无法直接实例化该类。而通过一个静态方法或静态变量,类提供了对唯一实例的访问。
单例模式的主要特点包括:
getInstance()
,用于获取单例实例。在该方法内部进行逻辑判断,如果实例变量为空,则创建一个新的实例并赋值给实例变量。随后的调用都直接返回已创建的实例。立即加载
,即在使用类的时候已经将对象创建完毕。简单
;没有多线程安全问题。耗费内存
。class Singleton {
// 1.私有化构造器
private Singleton() {
}
// 2.内部提供一个当前类的实例
// 4.此实例也必须静态化
private static Singleton single = new Singleton();
// 3.提供公共的静态的方法,返回当前类的对象
public static Singleton getInstance() {
return single;
}
}
延迟加载
,即在调用静态方法时实例才被创建。节约内存
。线程不安全
,根本不能保证单例的唯一性。
class Singleton {
// 1.私有化构造器
private Singleton() {
}
// 2.内部提供一个当前类的实例
// 4.此实例也必须静态化
private static Singleton single;
// 3.提供公共的静态的方法,返回当前类的对象
public static Singleton getInstance() {
if(single == null) {
single = new Singleton();
}
return single;
}
}
(先看完线程同步,在回过头看这个内容)
单例设计模式在多线程环境下可能存在线程安全问题,特别是懒汉式单例模式。为了解决线程安全问题,可以使用synchronized
关键字、双重检查锁定、静态内部类等机制来确保只有一个实例被创建,并提供线程安全的访问方式。
synchronized
关键字,使用同步锁保证只有一个线程能够进入临界区,但会降低性能。volatile
关键字修饰实例变量,以确保多线程环境下的可见性和有序性。在Java中,程序的入口点是main()
方法。为了使JVM能够调用main()
方法,它必须具有以下特征:
public
:main()
方法必须声明为public
,以便JVM能够访问它。static
:main()
方法必须声明为static
,因为在调用main()
方法时,JVM无需创建类的实例。main()
方法接受一个String
类型的数组参数(通常命名为args
),该数组保存执行Java命令时传递给程序的参数。static
代码块):
super()
调用超类的构造方法,或者通过this()
调用同一类中的其他构造方法。final
可以将实体声明为不可修改的,确保其数值或行为不会被改变。final
可以提供代码的安全性和稳定性,防止意外的修改和不必要的变动。final
可以用于性能优化,编译器可以进行更多的优化,提高执行效率。final
可以提供清晰的接口定义,减少对外部代码的依赖,促进代码的可维护性。final
用于声明不可变的实体,包括类、方法和变量。final
类:
final
的类**不能被继承**,即它是最终类。final
类中的方法默认为 final
,但可以被子类继承,除非它们被子类重写并标记为 final
。final
的类通常用于安全性、稳定性或效率等方面的考虑。final
方法:
final
的方法不能被子类重写或覆盖。final
方法在父类中定义实现,并且子类不能对其进行更改。final
方法可以被继承,但无法被子类修改。final
变量:
final
的变量是一个常量,一旦赋予初始值后,就不能再改变。final
变量必须在声明时初始化,可以通过直接赋值或构造方法进行初始化。final
变量通常使用大写字母表示,并使用下划线分隔单词(例如:MAX_SIZE
)。final
变量可以是基本数据类型(如 int
、char
等)或引用类型(如 String
、Object
等)。final
变量,引用本身是不可变的,但是对象的内部状态仍然可以修改。final
参数:
final
的方法参数表示该参数在方法内部不可修改。final
参数可以确保方法中不会意外地修改参数的值。final
和继承:
final
的类不能被继承。final
的方法不能被子类重写。final
的变量在被赋值后不能再修改。final
关键字的使用场景包括但不限于以下几种情况:
abstract
用于声明抽象类和抽象方法abstract
关键字声明的类。abstract
关键字声明的方法,没有方法体。模板设计模式(Template Design Pattern)是一种行为型设计模式,用于定义算法的框架结构,将算法的具体实现延迟到子类中。模板设计模式通过定义一个抽象类或接口作为算法的模板,并在其中定义算法的骨架,而将一些具体步骤的实现延迟到子类中。
在模板设计模式中,通常包含以下角色:
角色:
工作原理:
优点:
interface
关键字的详细信息interface
关键字来声明接口。public
),可以省略访问修饰符。public static final
。default
关键字进行声明和实现。static
关键字进行声明和实现。extends
关键字。implements
关键字来实现接口。特点 | 接口 (interface) | 抽象类 (abstract class) |
---|---|---|
实例化 | 不能实例化 | 不能实例化 |
构造函数 | 不能包含构造函数 | 可以包含构造函数 |
字段 | 不能包含字段 | 可以包含字段 |
方法 | 只包含方法声明,没有方法实现 | 可以包含方法声明和方法实现 |
多继承 | 支持多继承 | 不支持多继承 |
单继承 | 可以继承多个接口 | 只能继承一个抽象类 |
默认方法 | 可以包含默认方法 | 不支持默认方法 |
静态方法 | 可以包含静态方法 | 可以包含静态方法 |
访问修饰符 | 默认为公共(public) | 可以使用各种访问修饰符 |
构建范围 | 用于定义契约和协议,规范类的行为和能力 | 用于抽象概念和部分实现,提供共享代码和行为的能力 |
实现方式 | 类实现接口时使用implements关键字 | 类继承抽象类时使用extends关键字 |
设计目的 | 接口隔离,实现多态 | 提供共享代码和行为的能力,提供抽象概念 |
实例化要求 | 类要实现接口中定义的所有方法 | 类可以选择性地实现抽象类中的方法 |
常见设计模式 | 简单工厂、工厂方法、代理模式 | 模板方法设计模式 |
内部类是指在一个类的内部定义的类。Java中的内部类有四种类型:成员内部类、静态内部类、局部内部类和匿名内部类。
包装类(Wrapper Class)是Java中提供的一组类,用于将基本数据类型(如int、char、boolean等)封装成对象。每种基本数据类型都有对应的包装类,包装类提供了许多方法和功能,使得基本数据类型可以像对象一样进行操作。
Java对部分经常使用的数据采用缓存技术,在类第一次被加载时创建缓存和数据。当使用等值对象时直接从缓存中获取,从而提高了程序执行性能(通常只对常用数据进行缓存)。
在Java中,包装类与基本数据类型之间可以进行相等性比较。对于基本数据类型,可以直接使用关系运算符(如>
、<
、==
等)进行比较。而对于包装类,则需要使用equals()
方法进行比较。
在某些情况下,使用valueOf()
方法创建的包装类对象可以利用缓存技术,使得在一定范围内的比较结果为相等。
各个包装类的缓存范围和一些特殊注意事项:
需要注意的是,只有使用valueOf()
方法构造对象时才会使用缓存。使用new
方法等方式创建对象不会使用缓存。
故当使用valueOf()
方法创建包装类对象时,与基本数据类型进行大小比较时,在缓存范围内的值将被认为是相等的。这是因为它们引用了缓存中的同一个对象。