【Java】Java核心知识点与相应面试技巧(六)——类与对象(一)

发布于:2025-03-30 ⋅ 阅读:(27) ⋅ 点赞:(0)

Java 面向对象核心知识点(类与对象篇)

前言:
面向对象的本质:以类的方式组织代码,以对象的方式(组织)封装数据

1. 类与对象创建

定义是一种抽象的数据类型,类是对象的模板,定义对象的(静态的)属性和(动态的)行为。

1.1 类定义与实例化

public class Person {
    // 属性(字段)(成员变量)
    String name;
    int age;
    
    // 方法
    void speak() {
        System.out.println("I'm " + name);
    }
}

// 创建对象(类实例化后会返回一个自己类型的对象)
// p1就是Person类的一个实例
Person p1 = new Person();  // 使用 new 关键字创建对象,堆内存分配空间
p1.name = "Alice";         // 属性赋值
p1.speak();                // 方法调用

内存模型

栈内存(p1) → 堆内存(Person实例)
            ├─ name: "Alice"
            └─ age: 0

分析:栈(Stack)内存放的变量引用名,堆(Heap)内存放的是实际的对象属性值和方法。
Ps:多个引用变量可以指向同一个对象。

示例:Person p2 = p1; // p2 和 p1 指向同一对象

1.2 构造器详解

public class Student {
    String id;
    
    // 默认构造器(无参)
    public Student() {
        this.id = "0000"; // this指代当前对象,实例化初始值
    }
    
    // 带参构造器(重载),构造器支撑重载
    public Student(String id) {
        this();          // 调用无参构造器(必须首行)
        this.id = id;
    }
}

定义: 构造器用于创建对象时 初始化,与类同名,无返回值

关键规则

  • 构造器名必须与类名相同
  • 没有返回值类型(连void都没有)
  • 默认提供无参构造器(仅当没有自定义构造器时),而当存在有参构造器时必须显式定义无参构造器
  • this() 必须放在构造器首行
  • 在main方法中使用new 实例化对象,本质就是在调用构造器
public class Person {
    String name;
    int age;

    public Person() {
        this("Unknown", 0); // 调用另一个构造器
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

分析:

  • 构造器内部可调用 this(),但必须放在第一行
  • 构造器可用于初始化默认值,减少 setter 方法调用

2. 封装机制(Encapsulation)

定义: 封装 是面向对象的基本原则,目的是保护数据,防止外部直接访问。

2.1 访问控制修饰符

修饰符 类内 同包 子类 任意位置
private
default
protected
public

2.2 标准JavaBean

public class User {
	//使用 private 限制访问,确保属性(字段)只能在类内访问,也可以避免被直接修改
	private final String id;	//final 修饰不变对象,让变量不可变,提升线程安全
    private String username;
    private String password;
    
    // 提供公共方法
    // 使用 getter 和 setter 方法,初始化/获取变量方法
    public String getUsername() {
        return username;
    }
    
    public void setUsername(String name) {
        this.username = name;
    }
    
    // 其他方法...
}

封装优势

  • 数据保护(防止非法赋值)
  • 隐藏实现细节
  • 便于修改维护

3. 继承(Inheritance)与super

定义: 继承使得子类复用父类的属性和方法,使用 extends 关键字。

3.1 继承基础

//父类
class Animal {
    String name;

	public Animal(){
		System.out.println("Aniaml 无参构造执行");
	}
	
    void eat() {
        System.out.println("Eating...");
    }
}
//子类(派生类)Dog,继承父类(基类)的name属性和eat方法
class Dog extends Animal {  // 单继承
	public Dog(){
	//隐藏代码:调用了父类的无参构造
	super();
	Sywtem.out.println("Dog 无参构造执行");
	}
    void bark() {
        System.out.println("Woof!");
    }
}
public class InheritanceDemo {
	public static void main(String[] args){
		Dog dog = new Dog();  //自动调用构造器
		dog.name = "Buddy";
		dog.eat();  // 继承自 Animal
		dog.bark(); // Dog 自己的方法
	}
}

输出:
Aniaml 无参构造执行
Dog 无参构造执行
Eating…
Woof!

3.2 super关键用法

  • 调用父类构造方法
public class Animal {
    String name;

    public Animal(String name) {
        this.name = name;
    }
}

public class Dog extends Animal {
    public Dog(String name) {
        super(name); // 调用父类构造方法
    }
}

-调用父类方法

class Parent {
    int value = 10;
    
    void show() {
        System.out.println("Parent");
    }
}

class Child extends Parent {
    int value = 20;
    
    @Override
    void show() {
    	System.out.println(this.value); //访问该对象字段(20)
        System.out.println(super.value); // 访问父类字段(10)
        super.show();                    // 调用父类方法
    }
}

继承限制

  • Java不支持多继承(但支持多接口实现)
  • 父类private成员不可直接访问
  • final类 不能被继承

super规则:

  • 子类构造器中调用父类构造器super() 必须是第一行。(隐藏默认调用父类无参构造器)
  • super必须只能出现在子类的方法或构造方法中。
  • super和this不能同时调用构造方法。
  • 子类尽量使用 super 复用父类逻辑,避免代码重复。

4. 方法重写(Override)

4.1 重写规则

重写要求

  1. 方法名和参数列表完全相同
  2. 返回值类型相同或是子类(协变返回)
  3. 不能缩小访问权限(public -> protected ❌)(访问权限不能比父类更严格)
  4. 必须有 @Override 注解,防止拼写错误。
  5. 不能重写private/final/static方法
class Shape {
    public void draw() {
        System.out.println("Drawing shape");
    }
}

class Circle extends Shape {
    @Override  // 注解
    public void draw() {
        System.out.println("Drawing circle");
    }
    //如果可以,优先使用 super.method() 复用父类逻辑,减少代码重复。
}

ps:以上方法为非静态方法,若以父类引用指向子类

Shape s=new Circle();(子类的构造方法)
s.draw();

非静态方法调用的是对象的方法,输出Drawing circle
但如果使用static修饰静态方法,静态方法是同类加载的,调用的是的方法,输出Drawing shape

@Override作用

  • 编译器检查是否符合重写规则
  • 提高代码可读性

5.super 与 this 的区别

5.1 super

  • 作用

    • 用于访问父类的成员(字段、方法)。
    • 在子类构造器中调用父类构造器,确保父类部分正确初始化。
  • 使用场景

    • 访问父类方法:在子类重写方法中,调用父类原有方法的实现。
    • 访问父类字段:在子类中区分父类字段与子类字段(当名称相同时)。
    • 调用父类构造器:在子类构造器中,使用 super(...) 调用父类构造方法,必须位于构造器的第一行。
  • 示例

    class Parent {
        public int value = 10;
    
        public Parent(String msg) {
            System.out.println("Parent constructor: " + msg);
        }
    
        public void show() {
            System.out.println("Parent show");
        }
    }
    
    class Child extends Parent {
        public int value = 20;
    
        public Child(String msg) {
            super(msg); // 调用父类构造器,必须是第一行
            System.out.println("Child constructor: " + msg);
        }
    
        @Override
        public void show() {
            super.show(); // 调用父类方法
            System.out.println("Child show");
        }
    
        public void display() {
            System.out.println("Child value: " + this.value);
            System.out.println("Parent value: " + super.value);
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            Child child = new Child("Hello");
            child.show();
            child.display();
        }
    }
    

输出:
Parent constructor: Hello
Child constructor: Hello
Parent show
Child show
Child value: 20
Parent value: 10

5.2 this

  • 作用

    • 引用当前对象的成员(字段、方法)。
    • 在构造器中调用同一类中其他构造器,实现构造器重用。
  • 使用场景

    • 区分成员变量和局部变量:当参数名称与成员变量名称相同时,使用 this 表示当前对象的成员变量。
    • 调用本类其他构造器:在一个构造器中,通过 this(...) 调用同类中其他构造器,必须是构造器中的第一行。
  • 示例

    class Person {
        private String name;
        private int age;
    
        // 使用 this 调用其他构造器
        public Person() {
            this("Unknown", 0); // 调用带参构造器
        }
    
        public Person(String name, int age) {
            // 使用 this 区分成员变量与局部变量
            this.name = name;
            this.age = age;
        }
    
        public void introduce() {
            System.out.println("My name is " + this.name + ", age " + this.age);
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            Person p1 = new Person();
            Person p2 = new Person("Alice", 25);
            p1.introduce();
            p2.introduce();
        }
    }
    

    输出:
    My name is Unknown, age 0
    My name is Alice, age 25

5.3 总结对比

关键字 主要用途 使用位置 注意事项
super 访问父类成员,调用父类构造器 子类方法、构造器中 在构造器中,必须是第一行调用
this 表示当前对象,访问本类成员;调用本类其他构造器 本类方法、构造器中 在构造器中,this() 调用也必须放在第一行

6.重载(Overload)与重写(Override)的区别

6.1 重载(Overload)

  • 定义
    在同一个类中,方法名相同,但参数列表(参数个数或参数类型)不同。
    重载体现的是 编译时多态性(静态绑定)。

  • 特点

    • 返回类型可以相同也可以不同。(返回类型无法决定是否重载
    • 方法名必须完全相同;参数列表必须不同。
    • 与访问修饰符无关。
  • 示例

    public class Calculator {
        // 加法重载
        public int add(int a, int b) {
            return a + b;
        }
    
        public double add(double a, double b) {
            return a + b;
        }
    
        // 参数个数不同
        public int add(int a, int b, int c) {
            return a + b + c;
        }
    }
    

6.2 重写(Override)

  • 定义
    子类重写父类中已经存在的方法(方法名、参数列表必须一致),以提供新的实现。
    重写体现的是 运行时多态性(动态绑定)。

  • 特点

    • 必须保证方法名、参数列表完全一致。
    • 返回类型可以为父类返回类型的子类(协变返回类型)。
    • 访问权限不能比父类更严格(例如,父类方法是 public,子类不能重写为 protected 或 private)。
    • 建议使用 @Override 注解,帮助编译器检测是否正确重写了父类方法。
  • 示例

    class Animal {
        public void makeSound() {
            System.out.println("Animal sound");
        }
    }
    
    class Dog extends Animal {
        @Override
        public void makeSound() {
            System.out.println("Bark");
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            Animal animal = new Dog(); // 编译时为 Animal,但运行时为 Dog
            animal.makeSound(); // 输出 "Bark",运行时调用子类的方法
        }
    }
    

6.3 总结对比

特性 重载(Overload) 重写(Override)
定义 同一类中方法名相同,参数列表不同 子类中方法名、参数列表与父类完全一致
多态性 编译时多态性(静态绑定) 运行时多态性(动态绑定)
返回类型 可相同也可不同 必须与父类方法相同或为其子类(协变返回类型)
访问修饰符 与方法重载无直接关系 子类方法不能缩小父类方法的访问权限
注解 无特定要求 建议使用 @Override 注解

⚡ 高频面试题

  1. 创建对象时的内存分配过程?

  2. this和super能否同时出现?

  3. 以下代码输出什么?

    class A {
        int i = 10;
        void print() { System.out.println(i); }
    }
    
    class B extends A {
        int i = 20;
        public static void main(String[] args) {
            new B().print(); 
        }
    }
    

上文链接https://blog.csdn.net/weixin_73492487/article/details/146284259


网站公告

今日签到

点亮在社区的每一天
去签到