【基础篇】面向对象基础小结
面向对象基础小结
文章目录
面向对象和面向过程的区别
两者的主要区别在于解决问题的方式不同:
- 面向过程:是把解决问题的过程拆成一个个方法,通过一个个方法的执行解决问题。
- 面向对象:会先抽象出对象,然后用对象执行方法的方式解决问题。
面向对象开发的程序一般更易维护、易复用、易扩展。
求圆的面积和周长的示例
面向过程:
直接定义圆的半径,并使用该半径直接计算出圆的面积和周长(即将问题的过程拆分成了两个方法来解决)。
public class Main { public static void main(String[] args) { // 定义圆的半径 double radius = 3.0; // 计算圆的面积和周长 double area = Math.PI * radius * radius; double perimeter = 2 * Math.PI * radius; // 输出圆的面积和周长 System.out.println("圆的面积为:" + area); System.out.println("圆的周长为:" + perimeter); } }
面向对象:
定义一个 Circle
类来表示圆(即先抽象出一个对象),该类包含了圆的半径属性和计算面积、周长的方法(用对象的方法解决问题)。
public class Circle { // 定义圆的半径 private double radius; // 构造函数 public Circle(double radius) { this.radius = radius; } // 计算圆的面积 public double getArea() { return Math.PI * radius * radius; } // 计算圆的周长 public double getPerimeter() { return 2 * Math.PI * radius; } public static void main(String[] args) { // 创建一个半径为3的圆 Circle circle = new Circle(3.0); // 输出圆的面积和周长 System.out.println("圆的面积为:" + circle.getArea()); System.out.println("圆的周长为:" + circle.getPerimeter()); } }
创建一个对象用什么运算符?对象实体与对象引用有何不同?
用 new
运算符。
- new 创建对象实例(对象实例在堆内存中),
- 对象引用指向对象实例(对象引用存放在栈内存中)。
- 一个对象可以有 n 个引用指向它(可以用 n 条绳子系住一个气球)
- 一个对象引用可以指向 0 个或 1 个对象(一根绳子可以不系气球,也可以系一个气球)
对象的相等和引用相等的区别
- 对象的相等一般比较的是内存中存放的内容是否相等。
- 引用相等一般比较的是他们指向的内存地址是否相等。
String str1 = "hello"; String str2 = new String("hello"); String str3 = "hello"; // 使用 == 比较字符串的引用相等 System.out.println(str1 == str2); // false -- 一个在常量池中,一个在堆内存中 System.out.println(str1 == str3); // true -- 都在常量池中 // 使用 equals 方法比较字符串的相等 System.out.println(str1.equals(str2)); // true System.out.println(str1.equals(str3)); // true
构造方法有哪些特点?是否可被 override?
构造方法特点如下:
- 名字与类名相同。
- 没有返回值,但不能用 void 声明构造函数。
- 生成类的对象时自动执行,无需调用。
public class Person { private String name; private int age; // 构造方法没有返回值,并且不能用void声明构造函数 public Person(String name, int age) { this.name = name; this.age = age; } public void display() { System.out.println("Name: " + name); System.out.println("Age: " + age); } public static void main(String[] args) { // 生成对象时自动执行构造方法 Person person = new Person("John", 25); person.display(); } }
构造方法不能被 override(重写),但是可以 overload(重载),所以你可以看到一个类中有多个构造函数的情况
面向对象三大特征
面向对象编程的三大特征是:封装、继承和多态。
-
封装(Encapsulation):封装是将对象的属性和方法组合在一起,形成一个独立的、自包含的整体,对外部隐藏对象的内部细节,只向外部提供公共接口(方法),以便外部的代码能够通过这些接口访问对象。封装可以提高代码的可维护性和重用性,同时也可以保护对象的数据安全。
// 例如 封装一个实体类 public class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } } -
继承(Inheritance):继承是指在已有类的基础上,创建一个新的类,并且让新类拥有已有类的属性和方法。被继承的类称为父类或基类,继承的类称为子类或派生类。子类可以在不重复编写代码的情况下,拥有父类的公共属性和方法,同时还可以增加自己的属性和方法,以实现更加复杂的功能。
// 继承上面那个父类,下面这个是子类 public class Student extends Person { private int grade; public Student(String name, int age, int grade) { super(name, age); this.grade = grade; } public int getGrade() { return grade; } public void setGrade(int grade) { this.grade = grade; } } -
多态(Polymorphism):多态是指同一个方法调用,由于对象不同可能会产生不同的行为。多态可以让不同的对象对同一个消息做出不同的响应,从而提高代码的灵活性和可扩展性。多态有两种实现方式:静态多态(重载)和动态多态(重写和接口实现)。
-
在 Java 中,多态的实现主要依赖于两个机制:继承和方法重写。
-
调用子类中重写的
move()
方法,从而产生不同的行为。这就是多态的体现。
// 多态示例代码 public class Animal { public void move() { System.out.println("Animal move"); } } public class Dog extends Animal { public void move() { System.out.println("Dog move"); } } public class Cat extends Animal { public void move() { System.out.println("Cat move"); } } public class Main { public static void main(String[] args) { Animal a1 = new Animal(); Animal a2 = new Dog(); // 使用子类对象替换父类对象 Animal a3 = new Cat(); // 使用子类对象替换父类对象 a1.move(); a2.move(); a3.move(); } } -
注意,三个对象指定的都是 父类(Animal)
关于继承如下 3 点需要记住:
- 子类拥有父类对象所有的属性和方法(包括私有属性和私有方法),但是父类中的私有属性和方法子类是无法访问,只是拥有。
- 子类可以拥有自己属性和方法,即子类可以对父类进行扩展。
- 子类可以用自己的方式实现父类的方法。
子类无法直接访问父类的私有属性和方法
class ParentClass { private String privateProperty = "Private property"; public void publicMethod() { System.out.println("Public method"); } private void privateMethod() { System.out.println("Private method"); } } class ChildClass extends ParentClass { public void childMethod() { System.out.println("Child method"); System.out.println(publicProperty); // 子类可以访问父类的公有属性 publicMethod(); // 子类可以调用父类的公有方法 // 子类无法访问父类的私有属性和私有方法 // System.out.println(privateProperty); // 这行代码会报错 // privateMethod(); // 这行代码会报错 } } public class Main { public static void main(String[] args) { // 创建子类对象 ChildClass child = new ChildClass(); // 子类对象可以访问和调用父类的公有属性和方法 System.out.println(child.publicProperty); child.publicMethod(); } }
子类可以间接访问父类的私有成员 – 所以说拥有
class ParentClass { private String privateProperty = "Private property"; private void privateMethod() { System.out.println("Private method"); } public void accessPrivateMembers() { System.out.println(privateProperty); // 子类间接访问父类的私有属性 privateMethod(); // 子类间接调用父类的私有方法 } } class ChildClass extends ParentClass { // 子类继承了父类的私有属性和私有方法,但无法直接访问 public void accessParentPrivateMembers() { accessPrivateMembers(); // 子类间接访问父类的私有成员 } } public class Main { public static void main(String[] args) { ChildClass child = new ChildClass(); child.accessParentPrivateMembers(); } }
多态的特点:
- 对象类型(父类)和引用类型(子类)之间具有继承(类)/实现(接口)的关系;
- 引用类型变量发出的方法调用的到底是哪个类中的方法,必须在程序运行期间才能确定;
- 多态不能调用“只在子类存在但在父类不存在”的方法;(多态指向的都是父类)
- 如果子类重写了父类的方法,真正执行的是子类覆盖的方法,如果子类没有覆盖父类的方法,执行的是父类的方法。
接口和抽象类有什么共同点和区别?
interface
和 abstract
共同点:
- 都不能被实例化。
- 都可以包含抽象方法。
- 都可以有默认实现的方法(Java 8 可以用
default
关键字在接口中定义默认方法)。
区别:
- 【接口】主要用于对类的行为进行约束,你实现了某个接口就具有了对应的行为。【抽象类】主要用于代码复用,强调的是所属关系。
- 一个类只能继承一个类,但是可以实现多个接口。
- 【接口】中的成员变量只能是
public static final
类型的,不能被修改且必须有初始值,而【抽象类】的成员变量默认 default,可在子类中被重新定义,也可被重新赋值。
// 定义一个接口 public interface Animal { public void eat(); } // 定义一个抽象类 public abstract class Vehicle { private int speed; public void setSpeed(int speed) { this.speed = speed; } public int getSpeed() { return speed; } public abstract void run(); // 抽象方法 } // 实现接口 public class Dog implements Animal { public void eat() { System.out.println("The dog is eating."); } } // 继承抽象类 public class Car extends Vehicle { public void run() { System.out.println("The car is running."); } } // 测试类 public class Test { public static void main(String[] args) { // 使用接口 Animal animal = new Dog(); animal.eat(); // The dog is eating. // 使用抽象类 Vehicle vehicle = new Car(); vehicle.setSpeed(60); System.out.println("The speed of the car is " + vehicle.getSpeed() + " km/h."); // The speed of the car is 60 km/h. vehicle.run(); // The car is running. } }
深拷贝和浅拷贝的区别了解吗?什么是引用拷贝?
【深拷贝】会完全复制整个对象,会在堆上新创建一个地址(原对象的内部对象 Address
);
而【浅拷贝】只会在堆上新创建一个对象,但是内部地址还是原对象的,与原对象共用一个 Address
对象。
【引用拷贝】不会创建一个新的对象,而只是单纯的引用堆里面的原对象。
System.out.println("The speed of the car is " + vehicle.getSpeed() + " km/h."); // The speed of the car is 60 km/h. vehicle.run(); // The car is running. } }
深拷贝和浅拷贝的区别了解吗?什么是引用拷贝?
【深拷贝】会完全复制整个对象,会在堆上新创建一个地址(原对象的内部对象 Address
);
而【浅拷贝】只会在堆上新创建一个对象,但是内部地址还是原对象的,与原对象共用一个 Address
对象。
【引用拷贝】不会创建一个新的对象,而只是单纯的引用堆里面的原对象。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义