Java——面向对象深入了解(static、继承、多态、抽象类、接口、内部类、匿名类))

static关键字

在Java中,static关键字有多种用途,主要包括以下几个方面:

  • 静态变量:定义类级别的变量,也称为类变量。静态变量在类被加载到JVM时创建,并且只有一个副本,无论创建多少个该类的实例。所有对象共享同一个静态变量

    public class MyClass {
        public static int staticVar; // static修饰的静态变量
    }
    
  • 静态方法:静态方法属于类本身,而不是类的某个对象。静态方法只能直接访问类的静态成员,不能访问非静态成员。可以通过类名直接调用(推荐),也可以通过对象调用。常用于工具类的方法,如Math类中的Math.max()。

    public class MyClass {
        public static void staticMethod() {
            System.out.println("This is a static method.");
        }
    }
    
    MyClass.staticMethod() // 调用
    
  • 静态块静态代码块在类被加载时执行,且只执行一次。常用于初始化静态变量。这通常发生在以下情况之一:

  • 某个对象被创建时(即调用构造函数之前)。

  • 某个静态方法或静态变量被调用或访问时。

  • 使用Class.forName()等反射机制显式加载类时。

    public class MyClass {
        static {
            // 静态块代码
            System.out.println("Static block is executed.");
        }
    }
    
  1. 静态内部类:定义在另一个类内部的静态类。静态内部类不需要外部类的实例即可被访问。

    public class OuterClass {
        public static class StaticInnerClass {
            // 静态内部类的代码
        }
    }
    
  2. 静态导入:从某个类中导入静态成员到当前类中,这样在当前类中就可以直接使用这些静态成员而不必使用类名。

    import static java.lang.Math.PI;
    import static java.lang.Math.sqrt;
    
    public class MyClass {
        public double calculateCircleArea(double radius) {
            return PI * sqrt(radius);
        }
    }
    
  3. 静态导包:类似于静态导入,但是针对整个包。

    import static java.lang.*;
    
    public class MyClass {
        public void myMethod() {
            System.out.println("Hello, World!");
        }
    }
    

使用static关键字时需要注意,过度使用静态成员可能会导致代码难以维护和测试,因为静态成员的生命周期与应用程序的生命周期相同,且所有实例共享同一个静态变量,这可能会导致状态管理变得复杂。同时,静态方法无法访问实例变量和实例方法,这限制了它们的灵活性。

static的注意事项

● 静态方法只能访问静态变量和静态方法
● 非静态方法可以访问静态变量或者静态方法,也可以访问非静态的成员变量和非静态的成员方法
● 静态方法中是没有this关键字

工具类

在这里插入图片描述
在这里插入图片描述

构造代码块

构造代码块:

  • 1.写在成员位置的代码块
  • 2.作用:可以把多个构造方法中重复的代码抽取出来
  • 3.执行机制:在 创建类对象的时候会先执行构造代码块再执行构造方法
public class Student {  
    private String name;  
    private int age;  
    {  
        System.out.println("开始创建对象");  
    }  

    public Student() {  
    }  

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

构造代码块也可以在构造器里调用this()来代替

继承

当类与类之间,存在相同(共性)的内容,并满足子类是父类中的一种,就可以考虑使用继承,来优化代码

  • java中不允许一个子类继承多个父类,但是可以多层继承 (C++就可以多继承,C#也支持单继承)。
  • Java中所有的类都直接或者间接继承于Object类
  • 子类只能访问父类中非私有的成员(用private修饰的就不能访问)
  • 父类的构造方法不能被子类继承
  • 子类的全部构造器的第一行默认都是super()(写不写都有),它会先调用父类的无参构造器再执行自己的构造器
  • 如果父类有无参构造方法,那么父类就默认有无参构造器(就是有隐式的无参构造器),子类就也可以没有构造方法并成功创建对象。
  • 如果父类没有无参构造方法,子类必须定义构造方法,并通过 super 调用父类的有参构造器,才能成功创建对象。
    在这里插入图片描述
    在这里插入图片描述

使用公共的getter和setter方法访问父类的私有属性

在Java中,使用公共的getter和setter方法访问父类的私有属性是一种常见的做法,以保持封装性并允许对属性的访问和修改。这种方式允许父类控制其私有属性的访问,同时提供一种安全的方式来获取和设置这些属性的值。

以下是一个示例,展示如何在父类中定义私有属性,并提供公共的getter和setter方法,然后在子类中使用这些方法来访问和修改父类的私有属性:

class Parent {
    private int privateVar;

    // 公共的getter方法
    public int getPrivateVar() {
        return privateVar;
    }

    // 公共的setter方法
    public void setPrivateVar(int privateVar) {
        this.privateVar = privateVar;
    }
}

class Child extends Parent {
    public void accessParentProperty() {
        // 使用getter方法访问父类的私有属性
        int value = getPrivateVar();
        System.out.println("Accessed parent's private variable: " + value);

        // 使用setter方法修改父类的私有属性
        setPrivateVar(100);
        System.out.println("Modified parent's private variable to: 100");
    }
}

public class Main {
    public static void main(String[] args) {
        Child child = new Child();
        child.accessParentProperty();
    }
}

在这个例子中:

  1. 父类(Parent)定义了一个私有属性privateVar,并提供了公共的getter和setter方法来访问和修改这个属性。

  2. 子类(Child)继承了父类,并在其方法accessParentProperty中使用父类的getter和setter方法来访问和修改父类的私有属性。

  3. 主类(Main)创建了子类的实例,并调用accessParentProperty方法来演示如何访问和修改父类的私有属性。

这种方式的优点是:

  • 封装性:父类可以控制其私有属性的访问,防止外部直接访问和修改。
  • 灵活性:如果需要对属性的访问或修改添加额外的逻辑,可以在getter和setter方法中实现。
  • 继承性:子类可以通过继承父类的getter和setter方法来访问和修改父类的私有属性,而不需要知道属性的具体实现。

这种方法是Java中处理私有属性访问的标准做法。

方法重写

应用场景:当父类中方法,不能满足子类现在的需求时,我们就需要把这个方法进行重写。
注意

  • 子类中重写的方法上面需要加上@override
  • 如果方法重写了,那么就会覆盖掉父类方法,下一个类继承的是从写的方法。
  • 父类的静态方法不能被子类重写,但是可以被子类里的同名静态方法隐覆盖
    在这里插入图片描述

属性隐藏

class Animal {  
    String name = "动物";  
}  

class Dog extends Animal {  
    String name = "狗";  

    void showNames() {  
        System.out.println("Dog's name: " + name);          // 输出"狗"  
        System.out.println("Animal's name: " + super.name); // 输出"动物"  
    }  
}  

public class Main {  
    public static void main(String[] args) {  
        Dog dog = new Dog();  
        dog.showNames();  
    }  
}

在上面这段代码中,Dog继承了Animal,两个类里面都定义了name属性,但是Dog类里面的定义name覆盖了继承父类的name,所以Dog类里面调用name是"狗"。

this和super关键字

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  • 在静态方法中,super关键字是不允许使用。
  • super关键字不能用来调用父类中的静态方法和变量,如果要调用就 :父类名.方法&变量。

多态

多态是在继承/实现情况下的一种现象,表现为:对象多态、行为多态
多态的具体代码体现

People p1= new Student();
p1.run();
People p2 = new Teacher();
p2.run();

调用成员变量:编译看左边,运行也看左边
调用成员方法:编译看左边,运行也看右边

编译看左边:javac编译代码时,会看左边的父类中有没有这个变量(或方法),如果有,编译有,如果没有编译失败。

public class Test {  
    public static void main(String[] args) {  
        //创建对象(多态方式)  
        Animal a = new Dog();  
        System.out.println(a.name); //动物
        a.show(); // Dog --- show方法
    }  
}  

class Animal {  
    String name = "动物";  

    public void show() {  
        System.out.println("Animal --- show方法");  
    }  
}  

class Dog extends Animal {  
    String name = "狗";  

    @Override  
    public void show() {  
        System.out.println("Dog --- show方法");  
    }  
}

多态的前提

  • 有继承/实现关系;
  • 存在父类引用子类对象;
  • 存在方法重写。

多态的一个注意事项

多态是对象、行为的多态,Java中的属性(成员变量)不谈多态。

使用多态的好处

  • 在多态形式下,右边对象是解耦合的,更便于扩展和维护。

  • 定义方法时,使用父类类型的形参,可以接收一切子类对象,扩展性更强、更便利。

子类的弊端

多态下会产生的一个问题:多态下不能调用子类的特有功能
解决方法:强制类型转换
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

包和类

在这里插入图片描述
导包:用import

使用其他类的规则

  • 使用同一个包中的类时,不需要导包。
  • 使用java.lang(java的标准包)包中的类时,不需要导包。
  • Java的标准包其他情况都需要导包
  • 如果同时使用两个包中的同名类,需要用全类名。

final

跳转文章链接

权限修饰符

在这里插入图片描述
权限修饰符的使用规则实际开发中,一般只用private和public

  • 成员变量私有
  • 方法公开
  • 特例:如果方法中的代码是抽取其他方法中共性代码,这个方法一般也私有。

抽象类

抽象方法:将共性的行为(方法)抽取到父类之后。由于每一个子类执行的内容是不一样所以,在父类中不能确定具体的方法体该方法就可以定义为抽象方法。抽象方法在子类中必须强制重写,除非子类也是抽象类
抽象类:有抽象方法的类一定要定义为抽象类
在这里插入图片描述

抽象类的注意事项

  • 抽象类不能实例化。
  • 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类。
  • 可以有构造方法, 但不能创建对象。
  • 抽象类的子类要么重写抽象类中的所有抽象方法,要么也是一个抽象类。
  • 抽象类里可以有成员变量、方法、构造器
  • abstract 关键字只能用于修饰类、方法和接口,而不能用于修饰成员变量
    在这里插入图片描述
    在这里插入图片描述

模板方法

模板方法是父类(或抽象类)中能继承给子类且子类不能重写的方法,一般用public final在父类(或抽象类)中修饰该方法。
从而解决方法中存在重复代码的问题。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

接口

接口(Interface)是一种完全抽象的结构,它允许你定义方法,但是不实现它们。接口可以被类实现(implement),实现接口的类必须提供接口中所有方法的具体实现

使用注意

  • 接口不能创建对象。
  • 接口是用来被类实现的,实现接口的类称为实现类。
  • 一个类可以实现多个接口,实现类实现多个接口,就必须重写全部接口的全部抽象方法,否则实现类就要定义为抽象类。

接口中成员的特点

  • 成员变量只能是常量默认修饰符:public static final
  • 接口里的方法没有修饰符修饰只能是抽象方法,默认修饰符:public abstract
  • 接口里可以有抽象方法、默认方法、静态方法
  • 接口里的静态方法不能被重写(Override),但是可以被子类里同名的静态方法隐藏覆盖在这里插入图片描述在这里插入图片描述

接口和类之间的关系

  • 类和类的关系:继承关系,只能单继承,不能多继承,但是可以多层继承
  • 类和接口的关系:实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
  • 接口和接口的关系:继承关系,可以单继承,也可以多继承

接口里的默认方法(default void method())

  • 默认方法可以在接口中提供具体的实现代码,而其他类可以选择重写这个方法,重写的话就要去掉default关键字。
  • 类必须显式地重写该方法,以解决冲突。
  • 修饰符前面可以省略public,但是default不能。
  • 默认方法可以调用接口中的其他抽象方法或默认方法。

接口里的静态方法

  • 接口中的静态方法不能被实现该接口的类重写,因为静态方法是与接口本身相关联的。
  • 静态方法可以通过接口名直接调用,而无须实例化接口的实现类。

接口多态

interface Animal {  
    void makeSound(); // 抽象方法  
}  

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

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

public class Main {  
    public static void main(String[] args) {  
        // Animal接口不能实例化  
        // Animal animal = new Animal(); // 这将导致编译错误  

        // 实例化具体实现类  
        Animal myDog = new Dog(); // 创建Dog类的实例  
        Animal myCat = new Cat(); // 创建Cat类的实例  

        myDog.makeSound(); // 输出: Woof!  
        myCat.makeSound(); // 输出: Meow!  
    }  
}

接口实例化:
Animal myDog = new Dog();
在这里插入图片描述

接口和抽象类使用上的区别

接口: 用于定义一组方法的外部约定,一个类可以实现多个接口,强调的是“行为”。
抽象类: 用于提供一个模板,可以有部分实现,强调“共性”与“结构”,是一个类的蓝图。
如果希望实现多个不相关类之间的共同功能,接口是最佳选择;如果希望共享部分实现和状态,使用抽象类更为合适。

内部类

内部类表示的事物是外部类的一部分(单独出现没有任何意义)

内部类的访问特点

  • 内部类可以直接访问外部类的成员,包括私有外部类
  • 访问内部类的成员,必须创建对象

成员内部类

在这里插入图片描述
成员内部类定义在一个类的内部。成员内部类具有一些独特的特性,使其在某些场景中非常有用。以下是成员内部类的一些关键点:

特性

  1. 与外部类的关系

    • 成员内部类是外部类的一部分,可以直接访问外部类的所有成员(包括私有成员)。
  2. 实例化

    • 要创建成员内部类的实例,必须首先创建外部类的实例。语法如下:
      OuterClass outer = new OuterClass();
      OuterClass.InnerClass inner = outer.new InnerClass();
      
  3. 作用域

    • 成员内部类可以访问外部类的所有成员,包括静态和非静态成员。
  4. 多重实例

    • 每个成员内部类的实例都与其外部类的实例关联,因此可以创建多个成员内部类的实例,且每个实例都与不同的外部类实例关联。

使用场景

成员内部类通常在以下情境中使用:

  • 当需要访问外部类的私有数据或方法时,使用内部类可以简化代码的结构。
  • 当内部类的功能与外部类高度相关联时,将其作为内部类可以提高代码的封装性和可读性。

示例代码

以下是一个简单的成员内部类示例:

public class OuterClass {
    private String outerField = "Hello from OuterClass";
    
    public class InnerClass {
        public void display() {
            // 访问外部类的私有成员
            System.out.println(outerField);
        }
    }
    
    public void createInnerClass() {
        InnerClass inner = new InnerClass();
        inner.display();
    }
    
    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        outer.createInnerClass();
    }
}

在这个例子中,InnerClassOuterClass 的成员内部类。InnerClass 能够直接访问 OuterClass 的私有字段 outerField,并在 display 方法中打印出来。

public class Outer {  
    private int a = 10;  
    class Inner {  
        private int a = 20;  
        public void show() {  
            int a = 30;  
            // 调用外部类的属性
            System.out.println(Outer.this.a);  // 10  
            System.out.println(this.a);        // 20  
            System.out.println(a);             // 30  
        }  
    }  
}

静态内部类

在外部类中,可以定义一个静态内部类。它是外部类的一个静态成员,使用 static 关键字来定义。

静态内部类适用于以下场景:

  • 当静态内部类不依赖于外部类的实例时,使用静态内部类能使代码更加清晰。
  • 当需要组织类的逻辑,但不需要外部类的状态时,静态内部类是一个不错的选择。

静态内部类只能访问外部类的静态变量和静态方法,如果要访问外部的非静态成员就要创建外部类的对象。

 // 创建静态内部类的对象  
 // 只要是静态的东西,都可以用类名直接获取  
 Outer.Inner oi = new Outer.Inner();  
 oi.show1();

局部内部类

  1. 将内部类定义在方法里面就叫局部内部类,类似于方法里面的局部变量。
  2. 外界是无法直接使用,需要在方法内部创建对象并使用。
  3. 该类可以直接访问外部类的成员,也可以访问方法内的局部变量。

匿名内部类

匿名内部类: 隐藏了名字的内部类,可以写在成员位置,也可以写在局部位置。
匿名内部类的格式

new 类名或接口名() {  
    重写方法;  
};  

格式的细节
包含了继承或实现、方法重写、创建对象。
整体就是一个类的子类对象或接口的实现类对象。
使用场景
当方法的参数是接口或类时,以接口为例,可以传递这个接口的实现类对象,如果实现类只要使用一次,就可以用匿名内部类简化代码。
在这里插入图片描述
具体实现

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 from an anonymous inner class!");  
            }  
        };  
        
        greeting.greet();  
    }  
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值