类和对象

一、面向对象

1.1 面向对象与面向过程

是两种不同的编程范式

面向对象:先抽象出具有状态、行为的对象,然后用对象执行方法的方式解决问题,强调封装、继承、多态,更容易扩展和维护。因为修改一个对象不会影响到其他对象,适合处理复杂的系统

面向过程:将系统视为一系列的过程,通过调用这些过程来完成任务。强调的是算法和流程,如果需要修改一个过程,可能会影响到调用这个过程的其他地方

1.2 面向对象的三大特征

1.2.1 封装

为了提高代码的安全性,隐藏对象的内部细节,将对象的内部状态隐藏起来,并通过定义的公共的方法(接口)来操作对象,外部代码只知道如何使用这些方法而无需了解内部实现

1.2.2 继承

允许一个类(子类)继承另一个类(父类)的属性和方法的机制。子类可以重用父类的代码,并且可以通过添加新的方法或修改(重写)已有的方法来扩展或改进功能,提高了代码的可重用性和可扩展性

1.2.3 多态

是指相同的操作或方法可以在不同的对象上产生不同的行为,通过方法的重载和重写实现。多态允许以一致的方式处理不同类型的对象,提高了代码的灵活性

编译时多态

是指在编译阶段,编译器就能够确定调用哪个方法,这是通过方法的重载来实现的。编译时多态主要依赖于方法名和参数列表来确定调用的方法

public class Example {
 public int add(int a, int b) {
 return a + b;
 }
 public double add(double a, double b) {
 return a + b;
 }
 public static void main(String[] args) {
 Example example = new Example();
 int resultInt = example.add(2, 3); // 编译时确定调⽤add(int, int)
 double resultDouble = example.add(2.0, 3.0); // 编译时确定调⽤add(double, double)
 }
}
运行时多态

是指在程序运行时,根据实际对象的类型来确定调用的方法,这是通过方法的重写来实现的。运行时多态主要依赖于对象的实际类型,而不是引用类型

class Animal {
 void makeSound() {
 System.out.println("sound");
 }
}
class Dog extends Animal {
 @Override
 void makeSound() {
 System.out.println("Bark");
 }
}
public class PolymorphismExample {
 public static void main(String[] args) {
 Animal myDog = new Dog(); // 运⾏时多态,myDog的实际类型是Dog
 myDog.makeSound(); // 运⾏时确定调⽤Dog类的makeSound⽅法
 }
}
总结

1、编译时多态:通过方法的重载编译阶段确定调用的方法

2、运行时多态:通过方法的重写程序运行时确定调用的方法,实现动态绑定

二、接口和抽象类

2.1 定义区别

接口是一种抽象类型,它定义了一组方法,但没有实现任何方法的具体代码

抽象类是一个,可以包含抽象方法和具体方法。抽象类中的抽象方法是没有实现的方法,而具体方法则包含实现代码。抽象类不能直接实例化,通常需要子类继承并实现其中的抽象方法。

2.2 继承区别

接口支持多继承,一个类可以实现多个接口

Java中不支持多继承,一个类只能继承一个抽象类

2.3 构造器区别

接口不能包含构造器,因为接口不能被实例化

抽象类可以包含构造器,用于初始化抽象类的实例。当子类实例化时,会调用父类的构造器

2.4 访问修饰符

接口中的方法默认是public abstract的。接口中的变量默认是public static final的。

抽象类中的抽象方法默认是protected的,具体方法可以是public、protected或private

2.5 实现限制

类可以同时实现多个接口,实现接口的类必须提供接口中定义的所有方法

一个类只能继承一个抽象类,继承抽象类的子类必须提供抽象类中定义的所有抽象方法的实现

三、Java访问修饰符

访问权限:public > protected > 缺省 > private

3.1 public

表示对所有类可见

3.2 protected

表示对同一个包下的类所有子类可见

子类可以访问父类中声明为protected的成员,而不管子类与父类是否在同一个包中

3.3 缺省

表示只有同一个包中的类可以访问

3.4 private

表示对同一类内可见

四、static关键字

4.1 静态变量

使用static关键字声明的变量,也叫类变量。它们属于类而不是实例,所以所有实例共享相同的静态变量

4.2 静态方法

使用static关键字声明的方法。静态方法属于类而不属于实例,可以通过类名调用,而不需要创建类的实例

4.3 静态代码块

使用static关键字声明的代码块。它在类加载时执行,并且只执行一次

4.4 静态内部类

在类中使用static关键字声明的内部类

五、static和final

static用于修饰成员时,该成员成为类级别的,而不是实例级别的。静态成员属于类,而而不是属于类的实例。

public class MyClass {
 static int staticVariable; // 静态变量
 static void staticMethod() { // 静态⽅法
 // ...
 }
}
int value = MyClass.staticVariable;
MyClass.staticMethod();

当final用于修饰变量、方法或类时,表示它是不可变的。对于变量,一旦复制后不能再修改;对于方法,表示方法不能被子类重写;对于类,表示类不能被继承。

public class Example {
 final int constantValue = 42; // 不可变的变量
 final void finalMethod() { // 不可变的⽅法
 // ...
 }
}
final class FinalClass { // 不可变的类
 // ...
}

六、final、finally、finalize的区别

6.1 final

就是不可变的意思,可以修饰变量、方法和类。修饰变量时,这个变量必须初始化,所以也称为常量

6.2 finally

是异常处理的一部分,只能用在try/catch中,并且附带一个语句块表示这段语句一定会被执行,无论是否抛出异常

6.3 finalize

是java.lang.Object中的方法,也就是每个对象都有这个方法,一个对象的finalize方法只会调用一次,调用了也不一定被回收,因为只有对象被回收的时候才会被回收,就会导致前面调用,后面回收的时候出现问题,不推荐使用

七、方法的重载和重写

7.1 重载

是指在同一个类中,可以有多个方法具有相同的名称,但它们的参数列表不同(参数的类型、个数、顺序),具有以下特点。

1、方法的返回类型可以相同也可以不同

2、方法的重载与方法的访问修饰符和返回类型无关

3、编译器根据方法的参数列表来区分不同的重载方法

7.2 重写

是指在子类中重新定义父类中已经定义的方法方法名、参数列表和返回类型都必须相同

1、重写(子类)的方法不能比被重写(父类)的方法有更低的访问权限

2、子类方法不能抛出比父类方法更多的异常

7.3 总结

1、重载是在同一个类中定义多个方法,方法名相同,但参数列表不同

2、重写是在子类中重新定义父类中已有的方法,方法名和参数列表必须相同

3、重载与返回类型和访问修饰符无关,而重写要求方法签名相同(即方法名、返回值类型、参数列表)

4、重载是编译时多态,重写是运行时多态

八、深拷贝和浅拷贝

8.1 浅拷贝

创建一个新对象,然后将原对象的非静态字段复制到新对象。如果字段是基本数据类型,那么就复制其值;如果字段是引用类型,复制的就是引用而不是实际对象

// 浅拷⻉
class Person implements Cloneable {
 String name;
 Address address;
 @Override
 protected Object clone() throws CloneNotSupportedException {
 return super.clone();
 }
}
class Address {
 String city;
}
public class ShallowCopyExample {
 public static void main(String[] args) throws CloneNotSupportedException {
 Person person1 = new Person();
 person1.name = "John";
 person1.address = new Address();
 person1.address.city = "New York";
 Person person2 = (Person) person1.clone();
 System.out.println(person1 == person2); // false
 System.out.println(person1.address == person2.address); // true,引⽤对象共享
 }
}

8.2 深拷贝

创建一个新对象,复制原对象中所有引用类型的字段指向的对象,而不是共享引用。因此,新对象和原对象中的引用类型字段引用的是两组不同的对象

// 深拷⻉
import org.apache.commons.lang3.SerializationUtils;
class Person implements Serializable {
 String name;
 Address address;
 // 通过序列化和反序列化实现深拷⻉
 public Person deepCopy() {图源:javaguide
总结:
浅拷⻉复制对象,包括对象的引⽤,两者共享引⽤对象。
深拷⻉复制对象及其引⽤的对象,两者不共享引⽤对象,即使引⽤对象也会被复制。
在Java中,浅拷⻉通常通过 clone ⽅法实现,深拷⻉可以通过⼿动实现 clone ⽅法、序列化和反序列化,或
者使⽤第三⽅库来实现。
⾯向对象【笔记】 
本部分为⾯向对象的⼀些笔记整理,如不需要可以跳过。
 return SerializationUtils.clone(this);
 }
}
class Address implements Serializable {
 String city;
}
public class DeepCopyExample {
 public static void main(String[] args) {
 Person person1 = new Person();
 person1.name = "John";
 person1.address = new Address();
 person1.address.city = "New York";
 Person person2 = person1.deepCopy();
 System.out.println(person1 == person2); // false
 System.out.println(person1.address == person2.address); // false,引⽤对象不共享
 }
}

8.3 总结

1、浅拷贝复制对象,包括对象的引用,两者共享引用对象

2、深拷贝复制对象及其引用的对象,两者不共享引用对象

注意区分对象的引用和引用对象!

3、Java中,浅拷贝通常通过clone方法实现,深拷贝可以通过手动实现clone方法、序列化和反序列化,或者使用第三方库来实现 

  • 18
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值