JAVA面向对象

面向对象是一种以对象为中心的编程思想,通过指挥对象实现具体的功能

1. 类和对象

:类是现实世界中一种具有共同行为或者属性的事物的抽象。
对象:对象就是指在世界里真实的实体。
简单理解:类是对事物的一种描述,对象则为具体存在的事物

2. 封装

在编程中,封装(encapsulation)是一个核心概念,它确保了对象的内部状态不会被外部代码随意更改。这意味着对象的状态是私有的,外部代码只能通过定义好的接口来交互,而不能直接操作。封装的实践有助于保护对象的状态,同时清晰地区分公共接口和私有状态,通常是同(Private)关键字来进行声明。

3. 继承

在面向对象编程中,对于具有相似属性和方法的类,例如猫和狗都具备颜色属性以及跑跳等行为,且这些实现大致相同,每次为不同动物编写独立类会非常繁琐。为了简化这一过程并提高代码的复用性,我们可以使用继承。比如,可以创建一个名为Animal的基类,包含所有动物共有的属性和方法,然后让各个子类继承这个基类,从而获得这些属性和方法。

// 定义一个 Animal 类作为父类
class Animal {
    protected String name;

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

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

// 定义一个 Cat 类继承 Animal 类
class Cat extends Animal {
    public Cat(String name) {
        super(name); // 调用父类的构造方法
    }

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

// 定义一个 Dog 类继承 Animal 类
class Dog extends Animal {
    public Dog(String name) {
        super(name); // 调用父类的构造方法
    }

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

public class Main {
    public static void main(String[] args) {
        Cat cat = new Cat("Kitty");
        cat.eat();  // 调用父类的方法
        cat.meow(); // 调用子类的方法

        Dog dog = new Dog("Buddy");
        dog.eat();  // 调用父类的方法
        dog.bark(); // 调用子类的方法
    }
}

继承的特点:单继承,多层继承
子类能够继承父类的属性和法,但是当父类的方法不是子类所需要的方法时,子类就可以重写父类的方法。
重写的特点:

  1. 子类重写的方法名和参数列表(包括参数类型)和父类完全一样
class Animal {
    public void makeSound() {
        System.out.println("Animal is making a sound");
    }
}

class Dog extends Animal {
    // 重写父类方法,方法签名必须相同
    @Override
    public void makeSound() {
        System.out.println("Dog is barking");
    }
}

  1. 父类声明为私有的方法不可重写,被static和final修饰一样不能重写
class Animal {
    public static void makeSound() {
        System.out.println("Animal is making a sound");
    }

    public final void sleep() {
        // 休眠一段时间
    }
}

class Dog extends Animal {
    // 编译错误:不能重写被 final 修饰的方法
    // @Override
    // public void sleep() {
    //     // 休眠一段时间
    // }

    // 编译错误:不能重写被 static 修饰的方法
    // @Override
    // public static void makeSound() {
    //     System.out.println("Dog is barking");
    // }
}

  1. 子类方法的访问权限不能更低(例如父类为public 子类不能为private)
class Animal {
    public void eat() {
        System.out.println("Animal is eating");
    }
}

class Dog extends Animal {
    // 缩小访问修饰符是不允许的
    // @Override
    // private void eat() {
    //     System.out.println("Dog is eating");
    // }
}

  1. 子类方法不能抛出比父类方法更宽泛的异常
class Animal {
    public void sleep() throws InterruptedException {
        // 休眠一段时间
    }
}

class Dog extends Animal {
    // 编译错误:子类方法不能抛出比父类方法更宽泛的异常
    // @Override
    // public void sleep() throws Exception {
    //     // 休眠一段时间
    // }
}

4. 多态

通过上述例子,我们了解到可以通过继承来重用父类的属性或方法,这是因为我们的方法需求各不相同。那么,如果我们需要一个方法能够接收不同的对象并执行不同的操作,我们该如何实现呢?这就涉及到了多态的概念,多态允许同一个对象在不同的时刻展现出多种形态。
要想实现多态,有几个前提。

  • 要有继承或实现关系
  • 要有方法的重写
  • 要有父类引用指向子类对象
class Animal {
    public void eat(){
        System.out.println("动物吃饭");
    }
}

class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}

public class Test1Polymorphic {
    /*
        多态的前提:

            1. 要有(继承 \ 实现)关系
            2. 要有方法重写
            3. 要有父类引用, 指向子类对象
     */
    public static void main(String[] args) {
        // 当前事物, 是一只猫
        Cat c = new Cat();
        // 当前事物, 是一只动物
        Animal a = new Cat();
        a.eat();

    }
}

在访问成员的时候
成员变量:编译看父类,运行看父类
成员方法:编译看父类,运行看子类

class Fu {
    int num = 10;
    public void method(){
        System.out.println("Fu.. method");
    }
}

class Zi extends Fu {
    int num = 20;
    public void method(){
        System.out.println("Zi.. method");
    }
}
public class Test2Polymorpic {
    /*
         多态的成员访问特点:
                成员变量: 编译看左边 (父类), 运行看左边 (父类)
                成员方法: 编译看左边 (父类), 运行看右边 (子类)
     */
    public static void main(String[] args) {
        Fu f = new Zi();
        System.out.println(f.num);
        f.method();
    }
}

好处:使用多态的好处十分明显,在定义方法时,直接使用父类作为参数,在使用时用具体的子类类型参与操作。
缺点:不能使用子类的特有成员。

为了克服无法使用子类成员的限制,我们可以通过向下转型来访问子类的成员。这类似于我们之前学习的基本数据类型的强制转换,不同之处在于这次转换的是引用类型。子类型 对象名 = (子类型)父类引用;然而,就像基本数据类型强制转换可能导致精度降低一样,向下转型也有风险。如果尝试转换的对象不是该父类的子类实例,而是其他对象,就会抛出ClassCastException。因此,在转型前应进行检查,确认传入的变量确实是目标类型的实例,这可以通过使用(instanceof)关键字来实现。

abstract class Animal {
    public abstract void eat();
}

class Dog extends Animal {
    public void eat() {
        System.out.println("狗吃肉");
    }

    public void watchHome(){
        System.out.println("看家");
    }
}

class Cat extends Animal {
    public void eat() {
        System.out.println("猫吃鱼");
    }
}

public class Test4Polymorpic {
    public static void main(String[] args) {
        useAnimal(new Dog());
        useAnimal(new Cat());
    }

    public static void useAnimal(Animal a){  // Animal a = new Dog();
                                             // Animal a = new Cat();
        a.eat();
        //a.watchHome();

//        Dog dog = (Dog) a;
//        dog.watchHome();  // ClassCastException  类型转换异常
      
        // 判断a变量记录的类型, 是否是Dog
        if(a instanceof Dog){
            Dog dog = (Dog) a;
            dog.watchHome();
        }
    }

}

5. 抽象类和接口

抽象类

抽象类是什么?正如其名,它是一种抽象的类。在对比具体的概念时,具体类通常与直接的对象相对应,而抽象类则不会。它代表了一个抽象的概念。当我们在做子类共性功能抽取时,有些方法在父类中并没有具体的体现,这个时候就需要抽象类了。如果一个类不包含足够的信息来描述一个具体的对象,那么这个类就是抽象类,并且会用abstract关键字来修饰。当一个类不够具体时,就可以使用抽象类来表示更高层次的抽象。
抽象类的特点:

  • 构造方法:不能修饰构造方法
  • 构造块:不能修饰构造块
  • 属性:不能修饰属性
  • 方法:修饰的方法不能写代码,为模板作用,只能被子类继承重写
  • 继承:
    1. 可以被abstract类继承,继承过去的抽象方法可以选择性重写
    2. 被普通类继承时,必须重写抽象方法,或者变为抽象类
    3. 抽象类本身不能实例化
  • 类:可被修饰类,但不能被实例化,只能被继承,为模板作用,继承的类需要重写他的抽象方法
// 动物类
public abstract class Animal {
    public void drink(){
        System.out.println("喝水");
    }

    public Animal(){

    }

    public abstract void eat();
}
// 猫类
public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}
// 狗类
public class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗吃肉");
    }
}
// 测试类
public static void main(String[] args) {
        Dog d = new Dog();
        d.eat();
        d.drink();

        Cat c = new Cat();
        c.drink();
        c.eat();

        //Animal a = new Animal();
        //a.eat();
    }

猫狗存在共性内容,那就是eat,向上抽取出一个动物类(Animal)。但是父类无法将eat方法具体描述清楚,所以将其定义为抽象方法,实现只靠子类实现。

接口

接口(Interface)是 Java 编程语言中的一种引用类型,它是一种抽象的类型,定义了一组方法的规范,而不包含实现。在 Java 中,接口是实现多态和解耦的重要手段之一。以下是关于接口的详细描述:

  • 接口就是一种公共的规范标准,只要符合规范标准,大家都可以通用。
  • Java中接口存在的两个意义
    1. 用来定义规范
    2. 用来做功能的拓展
  • 接口不能实例化
    ​ 我们可以创建接口的实现类对象使用
  • 接口的子类
    ​ 要么重写接口中的所有抽象方法
    ​ 要么子类也是抽象类
// 接口
public interface Inter {
    public static final int NUM = 10;

    public abstract void show();
}
// 实现类
class InterImpl implements Inter{

    public void method(){
        // NUM = 20;
        System.out.println(NUM);
    }

    public void show(){

    }
}
// 测试类
public class TestInterface {
    /*
        成员变量: 只能是常量 系统会默认加入三个关键字
                    public static final
        构造方法: 没有
        成员方法: 只能是抽象方法, 系统会默认加入两个关键字
                    public abstract
     */
    public static void main(String[] args) {
        System.out.println(Inter.NUM);
    }
  
}

6. 代码块

在Java中,使用 { } 括起来的代码被称为代码块

  • 局部代码块:
    在方法中出现,用来限定变量的生命周期,及早释放,提高内存的利用率。
  • 构造代码块:
    在类中方法外出来呢,每次调用构造方法时都会执行,并且先于构造方法执行。
  • 同步代码块:
    同步代码块指的是被Java中Synchronized关键词修饰的代码块,在Java中,Synchronized关键词不仅仅可以用来修饰代码块,与此同时也可以用来修饰方法,是一种线程同步机制,被Synchronized关键词修饰的代码块会被加上内置锁。
  • 静态代码块:
    在类中方法外出现,使用static修饰,常常用来给类进行初始化,在加载的时候就执行,并且只执行一次。
    代码块的执行顺序:
    静态代码块->main()方法->构造代码块->构造方法->局部代码块

7. 内部类

内部类指的是定义在一个类里面的类。有多种形式,例如:

  • 成员内部类:
    成员内部类是定义在外部类中的类,地位通常和外部类的成员方法、变量地位类似。
    成员内部类可以访问外部类的所有成员,包括私有成员。
    成员内部类的实例必须使用外部类的实例来调用。
public class Outer {
    private int outerVar;

    public Outer(int outerVar) {
        this.outerVar = outerVar;
    }

    class Inner {
        public void display() {
            System.out.println("OuterVar: " + outerVar);
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Outer outer = new Outer(10);
        Outer.Inner inner = outer.new Inner();
        inner.display(); // 输出:OuterVar: 10
    }
}

  • 局部内部类:
    局部内部类通常定义在方法内部的类,作用域只在方法的内部。
    局部内部类可以访问外部类的成员,也可以访问方法内的局部变量。
    局部内部类在外界无法直接调用,需要在方法内实例化调用。
public class Outer {
    private int outerVar;

    public Outer(int outerVar) {
        this.outerVar = outerVar;
    }

    public void display() {
        class LocalInner {
            public void show() {
                System.out.println("OuterVar: " + outerVar);
            }
        }

        LocalInner inner = new LocalInner();
        inner.show();
    }
}

public class Main {
    public static void main(String[] args) {
        Outer outer = new Outer(10);
        outer.display(); // 输出:OuterVar: 10
    }
}

  • 匿名内部类:
    匿名内部类是一个没有类名的内部类,直接实现接口或者继承类,并在实例化时定义类的内容。
    匿名内部类通常是用了来创建临时性的、使用一次的类。
public interface Greeting {
    void greet();
}

public class Main {
    public static void main(String[] args) {
        Greeting greeting = new Greeting() {
            @Override
            public void greet() {
                System.out.println("Hello!");
            }
        };

        greeting.greet(); // 输出:Hello!
    }
}

  • 静态内部类:
    静态内部类是定义在外部类中,使用static修饰的内部类。
    静态内部类可以通过外部类访问,也可以直接实例化。
public class Outer {
    private static int outerVar;

    static class StaticInner {
        public void display() {
            System.out.println("OuterVar: " + outerVar);
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Outer.StaticInner inner = new Outer.StaticInner();
        inner.display(); // 输出:OuterVar: 0
    }
}

  • 总的来说:
    成员内部类适用于与外部类关系密切的情况下,需要访问外部类的成员。
    局部内部类用于方法内部需要一个特定功能的类。
    匿名内部类用于临时性、使用一次的类。
    静态内部类用于与外部类关系密切,但不需要访问外部类实例的情况。

8. 关键字

关键字在面向对象编程中扮演着重要的角色,它们用于定义类、方法、变量等,并控制其行为。以下是一些关键字在面向对象各个方面的作用:

  1. 类定义

    • class:用于定义类。
    • extends:用于表示继承关系,子类继承父类。
    • implements:用于表示实现接口,类实现接口中定义的方法。
    • abstract:用于定义抽象类,抽象类不能实例化,可以包含抽象方法。
    • interface:用于定义接口,接口中包含一组方法的规范,而不包含实现。
  2. 方法定义

    • void:表示方法没有返回值。
    • publicprotectedprivate、`默认:表示方法的访问权限。
    • static:表示方法是静态方法,可以通过类名直接调用。
    • final:表示方法是最终方法,不能被子类重写。
    • abstract:表示方法是抽象方法,只有方法签名,没有方法体。
  3. 变量定义

    • publicprotectedprivate:表示变量的访问权限。
    • static:表示静态变量,属于类,所有对象共享。
    • final:表示常量,不能再被赋值。
    • transient:表示变量不参与序列化。
    • volatile:表示变量是易变的,不会被缓存到线程本地内存中。
  4. 抽象类

    • public:默认使用public作为访问修饰符。
    • private:表示为私有方法,可以有方法体,并且不重写。
  5. 接口

    • public static final:成员变量默认修饰符。
    • public abstract:成员方法默认修饰符。
    • public default:默认方法,不是抽象方法,不被强制重写,可以在实现类中去掉default关键字选择重写。
    • private:私有方法,不是抽象方法,不可重写,默认方法可以调用私有的静态方法和非静态方法。
    • static:声明静态方法。
  6. 其他

    • this:表示当前对象的引用。
    • super:表示父类的引用。
    • new:用于创建对象。
    • instanceof:用于判断对象是否属于某个类或接口的实例。
    • return:用于从方法中返回值。

这些关键字在面向对象编程中起着重要的作用,通过合理使用这些关键字,可以定义出结构清晰、功能完善、易于维护的代码。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值