面向对象 _ 进阶 _ 三大特征
1. 关键字:this
- 构造器的主要作用是初始化对象的状态(属性和方法)。通过构造器,可以在对象创建时为成员变量赋初值,确保对象在使用前已处于有效状态。
- 另外,使用this访问属性和方法时,如果在本类中未找到,会从父类中查找。这个在继承中会讲到。
class Person{ // 定义Person类
private String name ;
private int age ;
public Person(String name,int age){
this.name = name ;
this.age = age ;
}
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age;
}
public void getInfo(){
System.out.println("姓名:" + name) ;
this.speak();
}
public void speak(){
System.out.println("年龄:"+ this.age);
}
}
this可以作为一个类中构造器相互调用的特殊格式。
- this():调用本类的无参构造器
- this(实参列表):调用本类的有参构造器
2. 面向对象的特征一:封装(Encapsulation)
- 概念:
封装是指将对象的属性(字段)和行为(方法)封装在一起,对外隐藏对象的内部实现细节,只暴露必要的接口(方法)供外部使用。封装有助于保护对象的内部状态,防止外部代码直接修改它,从而提高代码的安全性和可维护性。
-
特点:
-
私有化字段:通过将类的属性声明为
private
,限制外部访问。 -
提供公共访问方法:通过
public
的 getter 和 setter 方法来控制对这些私有属性的访问。 -
信息隐藏:外部只能通过公共方法与对象交互,不能直接访问或修改对象的内部数据。
-
例子:
public class Person {
private String name; // 私有化属性
private int age;
// 提供公共的 getter 和 setter 方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
在这个例子中,
Person
类的name
和age
属性是私有的,外部代码不能直接访问它们,只能通过getName()
和setName()
等方法来访问和修改。
优点:
- 安全性:通过限制直接访问,保护对象的内部状态。
- 灵活性:可以随时修改内部实现,而不影响使用该类的代码。
- 维护性:通过接口对外暴露行为,更容易维护和扩展代码。
3. 面向对象的特征二:继承(Inheritance)
- 概念:
继承是指一个类(子类)可以继承另一个类(父类)的属性和方法,从而实现代码的复用和层次化结构。通过继承,子类可以继承父类的所有功能,并且可以扩展或修改这些功能。
-
特点:
-
代码复用:子类可以复用父类的代码,不需要重新编写相同的代码。
-
方法重写:子类可以重写父类的方法,以实现特定的行为。
- 子类重写的方法
必须
和父类被重写的方法具有相同的方法名称
、参数列表
。 - 子类重写的方法使用的访问权限
不能小于
父类被重写的方法的访问权限。(public > protected > 缺省 > private) - 对比: 重载—>方法名相同,形参列表不同。不看返回值类型。
- 子类重写的方法
-
单继承:Java 中每个类只能继承一个直接父类,这被称为单继承。
-
继承层次:通过继承,可以形成类的层次结构(类的树形结构)支持多层继承
-
子类虽会继承父类私有 (private) 的成员变量,但子类不能对继承的私有成员变量直接进行访问,可通过继承的get/set方法进行访问
-
例子:
class Animal {
public void eat() {
System.out.println("Animal is eating");
}
}
class Dog extends Animal { // Dog 继承自 Animal
@Override
public void eat() { // 重写父类的方法
System.out.println("Dog is eating");
}
}
在这个例子中,
Dog
类继承了Animal
类,并且重写了eat()
方法。通过继承,Dog
类可以直接使用Animal
类中的方法,也可以根据需要重写它们。
优点:
- 代码复用:减少重复代码,提高开发效率。
- 层次化组织:通过继承,可以将类按照层次结构组织起来,便于管理和理解。
- 可扩展性:子类可以在父类的基础上进行扩展,添加新的功能。
4. 关键字:super
在 Java 中,super
是一个关键字,主要用于访问和调用父类的成员(包括字段、方法和构造器)。它在继承的概念中扮演着重要的角色,能够帮助子类更好地利用和扩展父类的功能。
4.1 访问父类的实例变量
当子类和父类有相同名称的成员变量时,子类的实例变量会覆盖父类的实例变量。这种情况下,super
关键字可以用于访问父类的实例变量。
例子:
class Parent {
String name = "Parent";
}
class Child extends Parent {
String name = "Child";
public void printName() {
System.out.println(name); // 输出: Child
System.out.println(super.name); // 输出: Parent
}
}
在这个例子中,子类
Child
的name
变量覆盖了父类Parent
的name
变量。如果想访问父类的name
,需要使用super.name
。
4.2 调用父类的方法
当子类重写(Override)了父类的方法时,如果在子类中需要调用被重写的父类方法,可以使用 super
关键字。
例子:
class Parent {
public void display() {
System.out.println("Parent display");
}
}
class Child extends Parent {
@Override
public void display() {
System.out.println("Child display");
}
public void show() {
super.display(); // 调用父类的display()方法
display(); // 调用子类的display()方法
}
}
在这个例子中,
Child
类重写了Parent
类的display()
方法。通过super.display()
,可以调用父类的display()
方法。
-
如果父类和子类中定义的实例变量名字不相同,那么它们在各自的类中是唯一的,子类不会“隐藏”或“覆盖”父类的实例变量。
-
权限修饰符(如
private
、protected
、public
、默认包访问权限)决定了子类是否可以直接访问父类的实例变量。- 如果父类的实例变量是
public
或protected
,或者是默认访问权限并且子类在同一个包中,那么子类可以直接访问这些变量。 - 如果父类的实例变量是
private
,则子类不能直接访问这个变量,而必须通过父类提供的getter
方法或构造器来间接访问。
- 如果父类的实例变量是
-
在子类中,如果权限修饰符允许,子类可以直接使用父类的实例变量名称来访问父类的实例变量。例如:
class Parent {
protected int age = 50;
}
class Child extends Parent {
public void printAge() {
System.out.println(age); // 直接访问父类的实例变量
}
}
this
关键字指代当前对象(即子类对象)。当子类访问一个实例变量时,如果这个实例变量在当前类中定义,this.变量
会指向当前类的变量;如果当前类中没有这个变量,this.变量
会访问父类中的变量。
class Parent {
protected int age = 50;
}
class Child extends Parent {
public void printAge() {
System.out.println(this.age); // 访问父类的实例变量,因为子类中没有age
}
}
super
关键字用来指代当前对象的父类部分。即使子类没有重名的实例变量,使用super.变量
明确表示我们希望访问父类中的变量。
class Parent {
protected int age = 50;
}
class Child extends Parent {
public void printAge() {
System.out.println(super.age); // 明确访问父类的实例变量
}
}
在没有重名变量时,子类对父类变量的访问是灵活的,可以直接访问,也可以通过
this
或super
关键字来访问,这三种方式效果相同。
4.3 调用父类的构造器
super
关键字的一个重要用途是在子类的构造器中调用父类的构造器。这通常用于初始化父类中的字段。
注意:
- 调用父类构造器的
super
语句必须是子类构造器中的第一条语句。 - 如果子类构造器中没有显式地调用父类构造器,Java 会默认调用父类的无参构造器。如果父类没有无参构造器,必须手动调用带参数的构造器。
例子:
class Parent {
public Parent(String name) {
System.out.println("Parent constructor: " + name);
}
}
class Child extends Parent {
public Child() {
super("ParentName"); // 调用父类的构造器并传递参数
System.out.println("Child constructor");
}
}
在这个例子中,
Child
类的构造器使用super("ParentName")
调用了Parent
类的构造器,并传递了参数。
4.4 this,super 对比
1、this和super的意义
this:当前对象
- 在构造器和非静态代码块中,表示正在new的对象
- 在实例方法中,表示调用当前方法的对象
super:引用父类声明的成员
2、this和super的使用格式
- this
- this.成员变量:表示当前对象的某个成员变量,而不是局部变量
- this.成员方法:表示当前对象的某个成员方法,完全可以省略this.
- this()或this(实参列表):调用另一个构造器协助当前对象的实例化,只能在构造器首行,只会找本类的构造器,找不到就报错
- super
- super.成员变量:表示当前对象的某个成员变量,该成员变量在父类中声明的
- super.成员方法:表示当前对象的某个成员方法,该成员方法在父类中声明的
- super()或super(实参列表):调用父类的构造器协助当前对象的实例化,只能在构造器首行,只会找直接父类的对应构造器,找不到就报错
5. 面向对象的特征三:多态(Polymorphism)
- 概念:
多态是指同一方法在不同对象中表现出不同的行为。多态是面向对象的核心特征之一,它允许一个接口可以有多种不同的实现方式,从而提高代码的灵活性和可扩展性。
-
特点:
-
方法重载:同一类中的多个方法可以有相同的名字,但参数不同。这些方法称为重载方法。
-
方法重写:子类可以重写父类的方法,使得子类对象调用这些方法时表现出不同的行为。
-
接口多态:一个对象可以被看作多种类型,允许使用父类或接口类型的引用指向子类对象。
-
例子:
class Animal {
public void makeSound() {
System.out.println("Animal sound");
}
}
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Woof");
}
}
class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("Meow");
}
}
public class Main {
public static void main(String[] args) {
Animal myDog = new Dog(); // Animal 类型的引用指向 Dog 对象
Animal myCat = new Cat(); // Animal 类型的引用指向 Cat 对象
myDog.makeSound(); // 输出: Woof
myCat.makeSound(); // 输出: Meow
}
}
在这个例子中,
myDog
和myCat
都是Animal
类型的引用,但它们分别指向Dog
和Cat
对象。调用makeSound()
方法时,会根据实际对象的类型来执行相应的方法,这就是多态的表现。
优点:
- 灵活性:代码可以适应多种情况,调用相同的方法可以表现出不同的行为。
- 可扩展性:通过多态,可以在不修改现有代码的情况下,轻松扩展新的功能。
- 接口与实现分离:通过多态,接口与具体实现分离,代码更清晰、更易维护。
总结:
- 封装:通过将数据和方法封装在类内部,保护对象的状态,控制外部访问。
- 继承:通过继承,子类可以复用父类的代码,并可以根据需要进行扩展和重写。
- 多态:通过多态,方法可以表现出不同的行为,使代码更加灵活和可扩展。