Java面向对象

一、类和对象

1.1 类和对象概述

​ 在 Java 中,类是一种用户自定义的数据类型,它描述了一组具有相同属性和行为的对象。一个类通常包含属性(也称为成员变量或字段)和方法(也称为函数或操作),这些属性和方法用于描述对象的状态和行为。

​ 对象则是类的实例。当程序创建一个类的对象时,它会在内存中分配空间来存储该对象的数据,并且调用对象的构造函数对其进行初始化。然后,可以通过对象访问该类中定义的属性和方法,从而对对象进行操作。

​ 简单地说,类是一种模板或蓝图,描述了对象的结构和行为,而对象则是类的实体表示,它封装了数据和行为,并允许我们对其进行操作。

public class Animal {  // Animal类
    String name;
    int age;

    public void eat() {
        System.out.println("Animal is eating.");
    }
}

public class TestAnimal{
    
    public static void main(String[] args){
        // 创建了两个Animal对象
        Animal animal1 = new Animal();  
        Animal animal2 = new Animal();
    }
}


1.2 类中成员讲解

类中定义的属性(变量)和方法为成员属性(变量)和成员方法

public class XXX {
	byte b; // 默认值为0
	short s; // 默认值为0
	String ss; // 默认值为null
    ....
}
默认值基本类型
byte0
short0
int0
long0L
float0.0f
double0.0d
char‘\u0000’ (unicode中的空字符)
booleanfalse
引用类型对象的初始值null
1.3 构造方法

先放上一个代码,看看什么是构造方法,然后在讲解其细节

public class Person {
    // 成员变量
    private int age;
    private String name;

    // 无参构造方法
    public Person(){
        
    }
    
    // 有参构造方法
    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

构造方法

  • 构造方法与类名相同且没有返回值
  • 只能在对象实例化的时候调用,一般指的就是使用new创建对象的时候,后续讲到反射再说其他的创建对象的方式
  • 当没有在类中编写构造方法时候,系统会自动添加无参的构造方法
  • 当在类中编写构造方法,无论是编写有参、无参的构造方法,系统都不会自动添加无参的构造方法
  • 一个类中可以有多个构造方法
1.4 this的使用

在Java中,“this” 关键字用于引用当前对象

  • 当实例变量和方法参数名称相同时,使用 “this” 关键字来引用实例变量。
  • 在构造函数中,使用 “this” 关键字调用其他构造函数,但必须是在构造方法的第一行出现
public class Person {
    // 成员变量
    private int age;
    private String name;

    // 无参构造方法
    public Person(){
        
    }
    
    // 有参构造方法
    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }
}
  • 在方法中,使用 “this” 关键字来调用另一个方法,一般this可以省略不写
public class Person {

    private int age;
    private String name;
    private String address;

    // 无参构造方法
    public Person(){

    }

    // 有参构造方法
    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }

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

二、封装

2.1 封装讲解

​ Java的封装是指将类的数据和方法包装在一起,隐藏实现细节,并提供公共接口以便其他代码可以使用。封装的主要目的是保护类的内部状态并防止外部代码直接访问对象的内部数据。

​ 在Java中,封装通过访问修饰符来实现。访问修饰符有public、private、protected和默认。

  • public表示该属性或方法可以被任何其他类访问;
  • private表示只有类自身的方法可以访问该属性或方法
  • protected表示该属性或方法可以被同一个包内的类和不同包中的子类访问
  • 默认表示该属性或方法可以被同一个包内的类访问。

​ 封装的另一个重要方面是getter和setter方法。getter方法用于获取私有属性的值,而setter方法用于设置私有属性的值。这样,我们就可以通过公共方法间接地访问私有属性,从而保护其安全性。

封装总结

  • 将类的某些信息隐藏在类的内部,不允许外部程序直接访问
  • 通过该类提供的方法类实现对隐藏信息的操作和访问(隐藏指的是通过private修饰的成员变量)
  • 隐藏对象的信息
  • 留出访问的接口
public class Person {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age < 0 || age > 150) {
            throw new IllegalArgumentException("Invalid age");
        }
        this.age = age;
    }
}

三、继承

3.1 继承讲解

继承:是面向对象软件技术中的一个概念。它使得复用以前的代码非常容易,能够大大缩短开发周期,降低开发费用。

​ 在Java语言中继承就是子类继承父类的属性和方法,使得子类对象(实例)具有父类的属性和方法,或子类从父类继承方法,使得子类具有父类相同的方法。父类有时也叫基类、超类;子类有时也被称为派生类。

​ 举个例子:动物有很多种,是一个比较大的概念。在动物中有猫(Cat)、狗(Dog)等动物,它们都有动物的一般特征(比如能够吃东西,要睡觉),不过又在细节上有区别(不同动物的吃的不同,睡觉方式不一样)。在Java语言中实现Cat和Dog等类的时候,就需要继承Animal这个类。继承之后Cat、Dog等具体动物类就是子类,Animal类就是父类。

代码如下:

// 动物类
public class Animal {
    private String name;
    private int age;

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

    public void eat() {
        System.out.println("Animal is eating.");
    }

    public void sleep() {
        System.out.println("Animal is sleeping.");
    }
}

// 猫类继承自动物类
public class Cat extends Animal {
    public Cat(String name, int age) {
        super(name, age);
    }

    public void meow() {
        System.out.println("Cat is meowing.");
    }
}

// 狗类继承自动物类
public class Dog extends Animal {
    public Dog(String name, int age) {
        super(name, age);
    }

    public void bark() {
        System.out.println("Dog is barking.");
    }
}

3.2 方法重载和方法重写
3.2.1 方法重载

​ 方法重载(Method Overloading)是指在一个类中定义多个同名的方法,但这些方法具有不同的参数列表。方法重载可以让程序员用同一个方法名实现不同的功能。在调用方法时,编译器会根据传入的参数确定具体调用哪个方法。

public class Calculator {
    
    public int add(int a, int b) {
        return a + b;
    }

    public double add(double a, double b) {
        return a + b;
    }
}

方法重载总结

  • 同一个类中
  • 方法名相同,参数列表不同(参数顺序,个数,类型)
  • 方法返回值、访问修饰符任意
  • 与方法的参数名无关
3.2.2 方法重写

​ 方法重写(Method Overriding)是指子类通过继承父类的方法,并对其进行重新实现。重写方法必须保持与原方法相同的方法名称、返回类型和参数列表,但可以改变方法的实现细节。重写方法在运行时会替换掉父类中的方法。

public class Animal {
    public void makeSound() {
        System.out.println("The animal makes a sound.");
    }
}

public class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("The dog barks.");
    }
}

方法重写

  • 有继承关系的子类中
  • 方法名相同,参数列表相同(参数顺序,个数,类型),方法返回值可以允许是子类类型
  • 访问修饰符,访问范围需要大于等于父类的访问范围
  • 与方法的参数名无关
3.3 继承总结
  • 一种类与类之间的关系
  • 使用已存在的类的定义作为基础创建新类
  • 新类的定义可以增加新的数据或新的功能
  • 新类可以用父类的功能,但不能选择性的继承父类
  • java 是单继承,这点不同于c++的多继承,但为了实现多继承的效果,java可以继承多个接口
3.4 super的使用

在Java中,super关键字表示一个对象的父类对象。它可以用于以下几种情况:

  1. 调用父类的构造函数:在子类的构造函数中使用super()调用父类的构造函数(必须出现在子类构造方法的第一行),并完成父类的初始化工作。如果子类没有显式地调用super(),则会自动调用父类的无参构造函数。
  2. 调用父类的方法:使用super.methodName()可以调用父类的方法。在子类中如果重写了父类的某个方法,并且想要在子类中调用该方法的父类实现,则可以使用super.methodName()来实现。
  3. 访问父类的属性:使用super.variableName可以访问父类的属性(不可以是private修饰的),并获取其值。
public class ParentClass {
    public ParentClass() {
        System.out.println("调用了ParentClass的构造函数");
    }
}

public class ChildClass extends ParentClass {
    public ChildClass() {
        super(); // 调用父类的构造函数
        System.out.println("调用了ChildClass的构造函数");
    }
}
3.5 初始化顺序

继承关系中的初始化顺序:父类静态成员——>子类静态成员——>父类构造对象——>子类构造对象

public class Animal {
    String name;
    int age;

   static {
        System.out.println("Animal static method");
    }

    public Animal(){
        System.out.println("Animal无参构造");
    }

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("Animal有参构造");
    }

    public void eat() {
        System.out.println("Animal is eating.");
    }
}

public class Dog extends Animal{
   static {
        System.out.println("Dog static method");
    }

    public Dog(){
        System.out.println("dog 无参构造");
    }

    public Dog(String name, int age) {
        super(name, age);
        System.out.println("dog有参构造");
    }
}

public class TestDog {
    public static void main(String[] args) {
        Dog dog = new Dog("阿黄",3);

    }
}

image-20230523113237934

四、多态

4.1 多态讲解

多态是面向对象编程中的一个重要概念,它允许我们使用不同的子类对象来调用同一个父类方法。

​ 多态的实现方式有两种,分别是方法重载和方法重写。方法重载是指在同一个类中定义多个方法,这些方法具有相同的名称但参数列表不同。当调用该方法时,会根据传入的参数类型来确定使用哪个方法。

​ 方法重写则是在子类中重新定义父类的方法,子类中的方法与父类的方法具有相同的名称、返回值类型和参数列表。当通过父类引用调用该方法时,会优先调用子类的方法。

实现多态还需要满足一些前提条件,包括:

  1. 子类必须继承父类
  2. 子类必须重写(覆盖)父类的方法
  3. 父类引用变量必须指向子类对象

代码展示

public class Animal {
    public void makeSound() {
        System.out.println("Animal makes sound");
    }
}

public class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Miao!");
    }
}

public class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Wang!");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal animal1 = new Cat();
        Animal animal2 = new Dog();
        animal1.makeSound(); // 输出 Miao!
        animal2.makeSound(); // 输出 Wang!
    }
}
4.2 多态的转型
4.2.1 向上转型
  1. 本质:父类的引用指向子类的对象
  2. 特点
  • 编译类型看左边,运行类型看右边
  • 可以调用父类的所有成员(需遵守访问权限)
  • 不能调用子类的特有成员
  • 运行效果看子类的具体实现
  1. 语法
父类类型 引用名 = new 子类类型();
Animal animal = new Dog();
//右侧创建一个子类对象,把它当作父类看待使用
4.2.2 向下转型

本质:一个已经向上转型的子类对象,将父类引用转为子类引用

特点:

  • 只能强制转换父类的引用,不能强制转换父类的对象
  • 要求父类的引用必须指向的是当前目标类型的对象
  • 当向下转型后,可以调用子类类型中所有的成员

语法

子类类型 引用名 = (子类类型) 父类引用;
//用强制类型转换的格式,将父类引用类型转为子类引用类型
Animal animal = new Dog();
Dog dog = (Dog) animal;
public class Animal {
    String name;
    int age;
    
    public Animal(){
        System.out.println("Animal无参构造");
    }
    
    public void eat() {
        System.out.println("Animal is eating.");
    }
}

public class Dog extends Animal{

    public Dog(){
        System.out.println("dog 无参构造");
    }


    @Override
    public void eat() {
       System.out.println("dog is eating");
    }
}

// 测试类
public class TestDog {

    public static void main(String[] args) {
        Animal animal = new Dog(); // 上转型
        Dog dog = (Dog) animal;  // 下转型
        dog.eat();

    }
}

image-20230523150553572

4.2.3 instanceof 关键词
public class TestDog {

    public static void main(String[] args) {
        Animal animal = new Animal();
        Dog dog = (Dog) animal;  // 转型失败,因为animal引用指向animal对象,不存在多态
        dog.eat();

    }
}

image-20230523150759243

为了应对上述转型的异常出现,引入 instanceof 关键字,用于判断对象的类型是否为XX类型或XX类型的子类型

格式:对象 instanceof 类名称

解释:返回值是boolean,也就是判断前面的对象能不能当作后面类型的实例

public class TestDog {

    public static void main(String[] args) {
        Animal animal = new Animal();
        if(animal instanceof Dog){
            System.out.println("可以向下转型");
            Dog dog = (Dog) animal;
            dog.eat();
        }else {
            System.out.println("不可以向下转型");
        }


    }
}

image-20230523151103978

多态中,子类对象指向父类引用后。父类中定义的可以被子类继承的方法,子类可以调用,如果子类重写了父类的方法,调用该方法时,调用的是子类重写的方法,子类特有的方法因为编译时在父类中不能检测出来,所以子类不能调用。

五、接口

​ 抽象类(使用abstract修饰的类)使用的很少,这里就不在讲解了。

​ 接口是一种特殊的抽象类,它定义了一系列方法的签名(即方法名称、参数类型和返回类型),但不提供这些方法的实现。相反,实现接口的类必须提供这些方法的具体实现。

​ 使用接口,则可以通过接口来约定类之间的交互方式,从而实现更灵活、可拓展的程序设计。

​ 具体地说,使用接口可以提高代码的可重用性和扩展性。当我们定义一个接口时,就定义了一个规范,任何实现该接口的类都必须实现接口中指定的方法。这样,我们可以编写针对接口而非具体实现的代码,使得代码更具有通用性和可拓展性。

public interface MyInterface {
  public void myMethod(); // 接口方法声明
}

public class MyClass implements MyInterface {
  public void myMethod() {
    System.out.println("实现MyInterface接口中的myMethod方法");
  }
}

额外小知识点

1 static 讲解
  • static + 属性:在内存中只有一份,叫静态成员或类成员。

    • 类对象共享,类加载时产生,销毁时释放,生命周期长
    • 访问方式:对象.成员 类名.成员
  • static + 方法 叫类方法或静态方法

    • 访问方式:对象.方法 类名.方法
  • static不可以修饰类,局部变量

    • 由于static修饰的变量在类加载时产生,而局部变量是在方法内部声明和定义的变量,在方法执行期间存在,所以不可以用static修饰局部变量
  • 静态方法中不能直接调用同一个类中的非静态方法,非静态属性,只能通过实例化后对象.方法或对象.属性调用,非静态方法中可以调用静态方法和非静态方法

2 final 讲解
  • final修饰的类是不能被继承的,因为其是一个最终类;
  • final修饰的变量是一个常量,只能被赋值一次;
  • final修饰的方法也不能重写,但能被重载;
  • final可以修饰类、方法、变量;
  • 内部类只能访问被final修饰的局部变量。
public class Animal {
    String name;
    int age;

    public final void print(){
        
    }
}

image-20230523144748900

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值