美文网首页
Day5—面向对象(静态、代码块、final、抽象、接口、内部类

Day5—面向对象(静态、代码块、final、抽象、接口、内部类

作者: OmewSPG | 来源:发表于2024-04-06 21:25 被阅读0次

static

某些特定的数据在内存空间里只有一份,或者多个对象共用这一份数据,可以用static关键字对其进行修饰。

主要用来修饰类的结构:属性、方法、代码块、内部类

使用static修饰属性
class Chinese{
    // 属性
    String name;
    int age;
    static String nation;   // 静态变量 
}
public class Static {
    public static void main(String[] args) {
        Chinese c1 = new Chinese();
        Chinese.nation = "CHN";   //可用通过“.”方法直接调用静态变量
        
        Chinese c2 = new Chinese();
        System.out.println(c2.nation);   // CHN
        
        // 静态变量的使用
        c1.nation = "China";
        System.out.println(c2.nation);   // China
内存解析图
  • 当一个属性可以被多个对象共享,那这个属性可以被声明为static
  • 静态变量:使用static修饰。如果创建类的多个对象,那么这多个对象共享一个静态变量
  • 静态变量随着类的加载而加载,且类的加载早于对象创建。故静态变量与具体的对象无关,而是归为类的所有。
  • 静态变量仅会加载一次,且存放在方法区中的静态域中
使用static修饰方法
class Chinese{

    // 方法
    public void eat(){

    }
    
    public static void show(){
           // 静态方法内部只能调用静态属性和静态方法
    }
    
}
// 静态方法的使用
        Chinese.show();     // 可通过类直接进行调用
        c1.show();
  • 静态方法: 静态方法随着类的加载而加载,可通过类直接进行调用
  • 静态方法中,只能调用静态的方法和属性
  • static方法中不能使用this、super关键字(因为static方法没有明确的对象指向)
  • 静态方法不能被重写
  • 工具类中的方法,习惯上也声明为static(省去造对象的过程):比如Math.random()
单例设计模式(Singleton)

单例设计模式:就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。

1、饿汉式

// 饿汉式
class Bank{
    
    // 1.构造器私有化
    private Bank(){
    }
    
    // 2.在类内部创建对象
    // 4.静态方法只能使用静态成员
    private static Bank bank = new Bank();
    
    // 3.公共方法,以便可以使用对象
    //   此方法设置为静态,以便返回同一个对象
    public static Bank getInstance(){
        return bank;
    }
}

2、懒汉式

// 懒汉式
// 暂未修复多线程问题
class Order{
    
    // 1.构造器私有化
    private Order(){
    }
    
    // 2.在类内部创建空对象,此时不会占用存储空间
    // 4.静态方法只能使用静态成员
    private static Order order = null;
    
    // 3.公共方法,以便可以使用对象,此时才会生成对象实例
    //   此方法设置为静态,以便返回同一个对象
    public static Order getInstance(){
        if(order == null)
            order = new Order();
        return order;
    }
}

注意:由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决

代码块

// 代码块
{
  内容
}

也叫做初始化块,用来对Java类或对象进行初始化
代码块只能用static进行修饰

静态代码块

静态代码块:用static 修饰的代码块

class Person{
    // 属性
    int age;
    String name;
    static String description = "default sentence...";
    
    // 代码块
    // 静态代码块
    // 在加载类的时候加载
    static{
        System.out.println("Hello static block!");
        description = "This is a static block!";    // 可修改静态属性
    }
}
  1. 可以有输出语句。
  2. 可以对类的属性、类的声明进行初始化操作。
  3. 不可以对非静态的属性初始化。即:不可以调用非静态的属性和方法。
  4. 若有多个静态的代码块,那么按照从上到下的顺序依次执行。
  5. 静态代码块的执行要先于非静态代码块。
  6. 静态代码块随着类的加载而加载,且只执行一次。
非静态代码块

非静态代码块:没有static修饰的代码块

class Person{
    // 属性
    int age;
    String name;
    static String description = "default sentence...";
    
    // 非静态代码块
    // 在创建对象的时候加载
    {
        System.out.println("Hello block!");
        age = 17;
        name = "Kana";
    }
}
  1. 可以有输出语句。
  2. 可以对类的属性、类的声明进行初始化操作。
  3. 除了调用非静态的结构外,还可以调用静态的变量或方法。
  4. 若有多个非静态的代码块,那么按照从上到下的顺序依次执行。
  5. 每次创建对象的时候,都会执行一次。且先于构造器执行。

final

final 可用于修饰类、方法、变量

  • 当final修饰类时,该类不能够被继承,比如(String类、System类、StringBuffer类)
  • 当final修饰方法时,该方法不能够被重写,比如:Object类中的getClass()
  • 当final修饰变量时,此变量就相当于一个常量,它可以被赋予初始值,但是不能够被修改
    1. final修饰属性时,可以对其进行:显示初始化、代码块中初始化、构造器中初始化
    2. final修饰形参时,表明此形参是一个常量。调用方法时,需要对该形参进行赋值,一旦赋值以后,就无法对其重新赋值
  • static final可以组合在一起使用,可以用来修饰属性和方法
    1. 当用来修饰属性时,该属性相当于一个全局常量
    2. 当用来修饰方法时,该方法随着类的加载而加载,并且不能够被重写

抽象类与抽象方法

将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类

// 定义抽象类
abstract class AbPerson{
    String name;
    int age;
    
    public AbPerson(){
    }
    
    public AbPerson(String name,int age){
        this.name = name;
        this.age = age;
    }
    
    public abstract void eat();   // 抽象方法
    
    public void walk(){
        System.out.println("walking...");
    }   
}

abstract可以修饰类和方法

当abstract修饰类:

  • 该类为抽象类,不能够被实例化;
  • 但仍可以有构造器,以便其子类实例化时使用。
//      AbPerson p1 = new AbPerson();  // 非法

当abstract修饰方法:

  • 为抽象方法,此方法不能被调用;
  • 抽象方法只能存在于抽象类中;
  • 只有方法的声明,没有方法体;
  • 子类只有重写父类的所有抽象方法后,才可以进行实例化,否则该子类也需要被abstract修饰。
class Student extends AbPerson{
    
    public Student(){
        super();
    }
    
    public Student(String name,int age){
        super(name,age);
    }
    
    // 重写抽象方法
    public void eat(){
        System.out.println("eating...");
    }
    
}

补充:使用抽象类的匿名子类

public class Abstract {

    public static void walk(AbPerson abPerson){
        System.out.println("name:"+abPerson.name+" age:"+abPerson.age);
        System.out.println("go to school!");
        abPerson.eat();
    }


    public static void main(String[] args) {

        // 补充:
        // 使用匿名对象
        walk(new Student("Kana",16));
        
        // 使用抽象类的匿名子类
        walk(new AbPerson("Kana",16){
            public void eat(){
                System.out.println("eating well");
            }
        });
        
    }
}

注意点:

(抽象类理所当然地应该被子类继承,并且子类可以实例化,否则这个抽象类就没有意义)

  • abstract不能修饰属性、构造器等结构
  • abstract不能用来修饰私有方法(因为继承的private方法不能重写)
  • abstract不能用来修饰静态方法(因为static方法由类直接加载,不能被覆盖)
  • abstract不能用来修饰final的方法和类(因为final修饰的方法不能重写,final类不能被继承)

接口

java中,class与Interface是两个并列的结构;
java不支持多重继承;但有了接口,就可以得到多重继承的效果。

在jdk7中:

接口只能定义全局常量(static final)与抽象方法(abstract)。接口是抽象方法和常量值定义的集合
注:接口不能定义构造器,所以接口不能够被实例化

interface Flyable{
    // 全局常量
    public static final int MAX_SPEED = 7900;
    int MIN_SPEED = 1;   // 也可以省略关键字
    
    // 抽象方法
    public abstract void fly();
    void stop();   // 也可以省略关键字
    
}

接口通过让类去实现的方式进行使用

class Plane implements Flyable{

    @Override   // 抽象方法的实现
    public void fly() {
        System.out.println("芜湖,起飞~");
    }

    @Override
    public void stop() {
        System.out.println("我的飞机没电了...");
    }
}

若实现类覆盖了接口中所有的抽象方法,则此类可以实例化;否则,此类必须被abstract修饰

      Plane p = new Plane();
      p.fly();

接口的具体使用体现了多态性
比如Kite类也通过Flyable实现:

class Kite implements Flyable{

    @Override   // 抽象方法的实现
    public void fly() {
        System.out.println("飞到天上去看看!");
    }

    @Override
    public void stop() {
        System.out.println("飞累了,休息一下~");
    }
}
        Flyable f1 = new Plane();
        Flyable f2 = new Kite();
        f1.fly();   //芜湖,起飞~
        f2.fly();   //飞到天上去看看!

通过接口,可以实现多继承:

// 接口之间可以多继承
interface AA{
}

interface BB{   
}

interface CC extends AA,BB{ 
}
jdk8中对于接口的改进

jdk8中的接口,除了jdk7的特性外,还可以定义静态方法默认方法

interface CompareA{
    
    // 静态方法
    public static void method1(){
        System.out.println("111");
    }
    
    // 默认方法
    public default void method2(){
        System.out.println("222");
    }
    
    default void method3(){    // 可省略public
        System.out.println("333");
    }
    
}

接口中的默认方法和静态方法都可以被重写,但需要注意以下几点:

默认方法:子类可以选择性地重写接口中的默认方法,如果子类重写了默认方法,就会使用子类中的方法实现,否则就会使用接口中的默认方法实现。需要注意的是,如果一个类实现了多个接口,并且这些接口中有相同的默认方法,那么在实现类中必须重写这个方法,否则会出现编译错误。

静态方法:接口中的静态方法不能被子类重写,因为它们是在编译时期间就确定的。子类可以定义一个同名的静态方法,但它只是一个新的方法,不是重写接口中的静态方法。

需要注意的是,接口中的默认方法和静态方法都可以在实现类中被调用,但调用方式有所不同。对于默认方法,可以通过实现类的对象来调用,默认方法会使用实现类中的方法实现,如果实现类没有提供实现,就会使用接口中的默认方法实现。对于静态方法,可以通过接口名直接调用,静态方法会使用接口中的方法实现。

总之,接口中的默认方法和静态方法都可以被重写,使用时需要注意方法签名和调用方式。

链接:https://www.jianshu.com/p/89d94fd4f256

class SubClass implements CompareA{

    // 可对静态方法进行重写
    public void method1(){
        System.out.println("111-111");
    }

    // 可对默认方法进行重写
    public void method2(){
        System.out.println("222-222");
    }

}
接口中的默认方法
  • 若一个接口中定义了一个默认方法,而另外一个接口中也定义了一个同名同参数的方法(不管此方法是否是默认方法),在实现类同时实现了这两个接口时,会出现:接口冲突。
    解决办法:实现类必须覆盖接口中同名同参数的方法,来解决冲突。
  • 若一个接口中定义了一个默认方法,而父类中也定义了一个同名同参数的非抽象方法,则不会出现冲突问题。因为此时遵守:类优先原则。接口中具有相同名称和参数的默认方法会被忽略。

内部类

java中允许将一个类A声明在类B中,类A称为内部类,类B称为外部类

成员内部类

作为外部类的成员:

  • 可以调用外部类的结构
  • 可以被static修饰
  • 可以被4种权限修饰符修饰

作为类出现:

  • 具有属性、方法、构造器等...
  • 可以被final修饰(不能被继承)
  • 可以被abstract修饰(不能被实例化)
class Character{
    
    String name;
    public void show(){
        System.out.println("Character");
    }
    
    // 静态内部类
    static class BB{
        String name;
        public void says(){
            System.out.println("BBB");
        }
    }
    
    // 非静态内部类
    class CC{
        String name;
        public void says(){
            System.out.println("CCC");
        }
        
        public void showCC(){
            Character.this.show();  // 调用外部类的方法
            this.says();
        }
    }
}
        // 静态内部类实例化
        Character.BB bb = new Character.BB();
        bb.says();
        
        // 非静态内部类实例化
        Character chara = new Character();
        Character.CC cc = chara.new CC();
        cc.says();
局部内部类

局部内部类可以存在于方法内、代码块内、构造器内;

class 外部类{

    方法(){
        class 局部内部类{...}
    }


    // 代码块
    {
        class 局部内部类{...}
    }

}

如何使用局部内部类

  • 只能在声明它的方法或代码块中使用,而且是先声明后使用。除此之外的任何地方都不能使用该类

  • 但是它的对象可以通过外部方法的返回值返回使用,返回值类型只能是局部内部类的父类或父接口类型

class Character{
    
    // 开发中并不常见的写法
    public void method(){
        
        // 局部内部类
        class AA{
            
        }
    }
    
    
    // 返回一个实现了Flyable接口的类的对象
    public Flyable getFlyable(){
        
        class Fighter implements Flyable{
            // 对接口的抽象方法进行重写(内容省略)
            public void fly(){ ... }
            public void stop(){ ... } 
        }

        return new Fighter();
    }

}

相关文章

  • java面向对象笔记

    面向对象三要素 抽象 接口 面向对象(局部内部类访问局部变量的问题) 匿名内部类

  • 面向对象总结

    面向对象思想 类与对象 定义类格式: 面向对象的三大特征 封装 继承 多态: 抽象类 接口 内部类 匿名内部类: ...

  • java static关键字的几种用法

    static:java静态修饰关键字 一:可修饰的对象包括 变量,代码块,方法,内部类,内部接口,静态导入包。二:...

  • 第二周 面向对象

    第二周 面向对象 2019.8.5 类 包含属性(准确说是field 域)、方法、构造方法、代码块、内部类/接口....

  • Java基础知识整理

    大纲 面向对象 关于Object类 重要关键字 内部类 抽象类与接口 编码 异常 一. 面向对象 1. 关于面向对...

  • 类的编译期与运行期

    非静态内部类 非静态内部类到底可以有静态属性吗? static成员变量,或者static final常量 非静态内...

  • Java面试核心框架

    常量池 常用关键字 final static 内部类 抽象类 接口 异常 注解 容器 内存管理内存模型、工作内...

  • Day09

    学习了,abstract. final. 内部类,包,继承,接口,interface 和implements 抽象...

  • Java面向对象,继承,this,super,重写,final

    day08笔记【Java面向对象,继承,this,super,重写,final】 1_面向对象(代码块的概述和分类...

  • 13-面向对象

    内容: final static 匿名对象 内部类 包的声明与访问 四种访问修饰符 代码块 1. final关键字...

网友评论

      本文标题:Day5—面向对象(静态、代码块、final、抽象、接口、内部类

      本文链接:https://www.haomeiwen.com/subject/lnwatjtx.html