Java面向对象(下)

Java面向对象(下)

1. static关键字

static可以用来修饰类的内部结构(除了构造器):属性、方法、代码块、内部类

1.1 静态属性

  1. 用static修饰的属性为静态属性(类变量),非静态变量(或称实例变量)
  • 实例变量:每个对象都有属于自己的一套非静态属性,互不影响
  • 类变量:所有对象共用的。当通过一个对象修改静态变量,会导致其他变量调用此静态变量时,得到的是修改过的数值。
  1. 静态变量随着类的加载而加载,早于对象的创建。
    而实例变量是在对象创建后才加载的
    所以可以通过 “类.静态变量” 的方式进行调用
  2. 静态变量存储在方法区的静态域中
  3. 静态属性举例:System.out , Math.PI
class Chinese{
    String name;
    int age;
    static nation;
}
class Test{
    public static void main(String[] args){
        //不用创建对象,就可以调用静态变量
        //因为静态变量随着类的加载而加载
        Chinese.nation = "CHINA";
    }
}

1.2 静态方法

  • 随着类的加载而加载,可以通过 类.方法 来调用方法
  • 静态方法中只能调用静态的方法、静态的属性(由生命周期决定)
  • 非静态方法既可以调用静态的,也可以调用非静态的
  • 在静态的方法内,不能使用this,super关键字

1.3 什么时候声明为static

属性

  1. 该属性是被多个对象共用的,不会随着对象的不同而不同
  2. 类中的常量也常被修饰为static,如Math.PI
    方法
  3. 操作静态属性的方法,通常为static
  4. 工具类中的方法,比如Math类、Arrays类、Collections类

2.单例设计模式

2.1 什么是设计模式

  • 设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格以及解决问题的思考方式。类似于棋谱。
  • 设计模式是独立于语言的(和数据结构类似),对Java、Python等编程设计都适用

2.2 单例设计模式

  • 单例设计模式的类只能由一个对象
    实现方式
  1. 将构造器设置为private的(这样类的外部就不能创建对象了)
  2. 在类的内部创建静态的类对象instance
  3. 声明public的静态方法getInstance(),返回类内部创建的对象

2.3 饿汉式和懒汉式

//单例设计模式
//饿汉式
public class SingletonTest1 {
    public static void main(String[] args) {
        Bank b1 = Bank.getInstance();
        Bank b2 = Bank.getInstance();
        //地址值相同,说明这个类只有一个对象
        System.out.println(b1 == b2);
    }
}

class Bank {
    //私有化类的构造器
    private Bank() {

    }

    //内部创建类的对象
    private static Bank instance = new Bank();

    //声明public,static的getInstance方法,返回内部创建的类
    public static Bank getInstance() {
        return instance;
    }
}
//单例模式
//懒汉式
public class SingletonTest2 {
    public static void main(String[] args) {
        Order order1 = Order.getInstance();
        Order order2 = Order.getInstance();
        System.out.println(order1 == order2);
    }
}

class Order{
    private Order(){

    }

    private static Order instance = null;

    public static Order getInstance(){
        if(instance == null){
            instance = new Order();
        }
        return instance;
    }
}

饿汉式和懒汉式的比较

  • 饿汉式:
    1. 坏处:对象加载时间过长
    2. 好处:饿汉式是线程安全的
  • 懒汉式:
    1. 好处:延迟对象的创建
    2. 目前的写法的坏处是线程不安全,到多线程时,可以修改

2.4 单例模式的使用场景

因为只生成一个对象,所以减少了系统的开销
[外链图片转存中…(img-KUsvedLP-1672233930225)]

3. main方法的理解

  1. main方法是程序的入口
  2. main方法也是一个普通的静态方法
  3. main()也可以作为我们与控制台交互的方式

4. 代码块(初始化块) 类的成员之四

  1. 代码块又称初始化块,作用是初始化类、对象
  2. 代码块如果有修饰的话,只能使用static
  3. 根据是否用static修饰分为:静态代码块、非静态代码块
class Person{
    //非静态代码块
    {
        
    }
    //静态代码块
    static{

    }
}

4.1 静态代码块

  1. 内部可以有输出语句
  2. 随着类的加载而执行,因而只会执行一次
  3. 可以初始化类的静态属性
  4. 如果一个类中定义了多个静态代码块,则先声明的静态代码块先执行
  5. 而所有的静态代码块的执行都先于非静态的代码块(因为静态代码块随着类的加载而执行,先于对象的创建)
  6. 静态代码块只能调用静态的结构

4.2 非静态代码块

  1. 内部可以有输出语句
  2. 随着对象的创建而执行,每创建一个对象就会执行一次非静态代码块
  3. 可以在创建对象的时候,对属性进行初始化
  4. 多个非静态代码块,执行顺序也是先声明先执行
  5. 非静态代码块既可以调用静态结构也可以调用非静态结构

5. 对属性赋值

数字表示赋值的先后顺序

  1. 默认初始化
  2. 显示初始化 代码块中初始化
    哪个先写,哪个先赋值
  3. 构造器中初始化
  4. 使用对象.属性赋值

6.final 关键字

final —— 最终的(不可修改)
final可以用来修饰类、方法、变量

6.1 final修饰类

final类不能有子类,不能被继承
比如String类、System类、StringBuffer类

6.2 final修饰方法

表示此方法不能被重写

6.3 final修饰变量

final修饰变量,此时的变量就称为一个常量

  1. final修饰属性:可以赋值的位置:显示初始化、代码块初始化、构造器初始化
  2. final修饰局部变量:表示常量,只能调用,不能修改。
    尤其是用final修饰形参时,在方法中只能使用,不能修改

6.4 static final

static final修饰属性:全局常量

7. abstract关键字

abstract 可以用来修饰类和方法

7.1 抽象类

抽象类不能实例化,只能被其他类继承

  • 抽象类一定有构造器,便于子类实例化时调用
    1. 若子类重写了所有的抽象方法,则此子类可以实例化
    1. 否则,此子类也是抽象类,需要用abstract来修饰

7.2 抽象方法

抽象方法只有方法的声明,没有方法体

  • 包含抽象方法的类一定时抽象类,反之抽象类中不一定有抽象方法
public abstract void eat();

注意点

  1. 什么时候用抽象类呢?
    举个例子:几何图形这个类就是抽象的,计算面积这种方法只能声明,不能实现。
  2. abstract不能用来修饰私有方法、静态方法、final的方法、final的类

7.3 抽象类的匿名子类

  • 一些抽象类因为有抽象方法,需要将抽象方法重写了才能创建对象
  • 目的:匿名子类只需要使用一次(省事)
//假设Person是一个抽象类
//Person中eat方法是抽象方法

//创建匿名子类,把抽象类的抽象方法给实现了
//使用多态将子类对象赋给父类的引用
Person p = new Person(){
    public void eat(){
        System.out.println("你要好好吃饭啊");
    }
}

7.4 模板方法设计模式

简单的说,像是填空题,把确定的写好了,不确定的暴露出去,让子类去实现
image.png

import java.time.format.TextStyle;

import javax.sound.midi.SysexMessage;

//模板方法设计模式
public class TemplateTest {
    public static void main(String[] args) {
        Template test = new SubTemplate();
        test.spendTime();
    }
  
}


//一个计算代码运行时间的类模板
abstract class Template{
    public void spendTime(){
        long start = System.currentTimeMillis();

        code();
        
        long end = System.currentTimeMillis();

        System.out.println("代码运行的时间为"+(end - start));
    }

    public abstract void code();
}


class SubTemplate extends Template{

    @Override
    public void code() {
        // TODO Auto-generated method stub
        for(int i = 2;i<=1000;++i){
            boolean isPrime = true;
            for(int j = 2;j<=Math.sqrt(i);++j){
                if((i%j==0)){
                    isPrime = false;
                }
            }
            if(isPrime){
                System.out.println(i);
            }
        }
        
    }

}

8. 接口 interface

  • 接口的本质是契约、标准、规范
  • 继承表达的是"是不是"的关系(is a)(例如Student is a Person),而接口实现的是"能不能"的关系,比如这个电器能不能实现USB接口
  • Java类不能多重继承,但是接口可以实现多重继承
  • Java中类和接口的地位是并列的
    image.png

8.1 接口的成员

  1. JDK7及以前
    只能定义全局变量抽象方法
  • 全局常量:public static final,可以省略
  • 抽象方法:public abstract,可以省略
  1. JDK8
    除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法

8.2 接口的实现和使用

  • 接口中不能定义构造器,意味着接口不能实例化
  • Java中,接口interface通过类class去实现(implements)的方法来使用
  • 如果类覆盖了接口中的所有抽象方法,则此类就可以实例化
  • 如果实现类没有覆盖接口中所有的抽象方法,则此类为抽象类
  • Java类可以实现多个接口,不同接口之间用逗号隔开
  • 接口的使用体现多态性
//格式
//先写继承,再写实现
class Plane extends Machine implements Flyable,Attackable{

}

接口和接口之间可以多继承
下面的接口C中有了A和B中的定义的抽象方法

interface A{
    public abstract void method1();
}

interface B{
    public abstract void method2();
}

interface C extends A,B{

}

接口的使用体现了多态性

/*
 * 接口的使用体现多态
 */
public class USBTest {
    public static void main(String[] args) {
        Computer computer = new Computer();
        // 接口多态性的体现
        // 将实现了USB接口的Flash对象传给USB接口
        computer.transfer(new Flash());
    }
}

interface USB {
    void start();

    void end();
}

// 实现USB接口的Flash
class Flash implements USB {
    public void start() {
        System.out.println("Flash开始工作");
    }

    public void end() {
        System.out.println("Flash结束工作");
    }
}

class Computer {
    public void transfer(USB usb) {
        usb.start();

        System.out.println("数据传输中....");

        usb.end();
    }
}

8.3 代理模式 接口的应用

//接口的应用:代理模式
interface NetWork {
    void browse();
}

// 被代理类
class Server implements NetWork {
    public void browse() {
        System.out.println("真实的服务器访问");
    }
}

// 代理类
class ProxyServer implements NetWork {
    private NetWork work;

    public ProxyServer(NetWork work) {
        this.work = work;
    }

    public void check() {
        System.out.println("联网前的检查");
    }

    public void browse() {
        check();
        work.browse();
    }

}

public class NetWorkTest {
    public static void main(String[] args) {
        Server server = new Server();
        ProxyServer proxyServer = new ProxyServer(server);

        // 通过接口的多态性,在代理服务器的方法中调用了Server中的方法
        proxyServer.browse();
    }
}

8.4 JDK8接口新特性

还可以定义静态方法默认方法

interface A{
    public static void method1(){
        System.out.println("接口中的静态方法");
    }

    public default void method2(){
        System.out.println("接口中的默认方法");
    }
}
  • 接口中的静态方法,只能通过接口来调用,实现类不能用
//静态方法通过接口来调用,和工具类有点相似
A.method1();
  • 默认方法可以通过实现类的对象调用,实现类还可以重写接口中的默认方法
  • 类优先原则如果实现类(同时是子类)继承的父类和实现接口中声明了同名同参数的方法,那么子类在没有重写此方法的情况下。默认调用的是父类中的同名同参数的方法
  • 如果多个接口中定义了同名同参的默认方法,实现类实现了多个接口,那么实现类会在没有重写该方法的情况下报错。这需要我们对方法进行重写
    在实现类的方法中调用接口中默认方法
class SubClass implements A{
    public void method2(){
        System.out.println("Subclass:method2");
    }

    public void method3(){
        //调用接口中默认方法
        //接口名.super.默认方法名
        A.super.method2();
    }
}

9. 内部类 类的内部成员五

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

内部类的分类

  1. 成员内部类(静态、非静态)
  2. 局部内部类
    • 方法内
    • 代码块内
    • 构造器内

9.1 成员内部类

一方面,作为外部类的成员

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

另一方面,作为一个类

  • 定义属性、构造器、方法、代码块
  • 可以用final修饰,表示不能被继承;换个角度,不用final就可以被继承
  • 可以用abstract修饰,表示不能被实例化

关注3个问题

  • 如何实例化成员内部类的对象
  • 如何在成员内部类中区分调用外部类的结构
  • 开发中局部内部类的使用
//成员内部类的一些测试
public class InnerClass {
    public static void main(String[] args) {
        //静态内部类的实例化
        Person.Dog dog = new Person.Dog();
        dog.show();

        //非静态内部类的实例化
        Person p = new Person();
        Person.Bird bird = p.new Bird();
        bird.sing();
        bird.display();
    }
}


class Person{
    String name = "小明";
    //静态成员内部类
    static class Dog{
        String name = "大黄";
        void show(){
            System.out.println("小狗汪汪");
        }
    } 

    //非静态成员内部类
    class Bird{
        String name = "杜鹃";
        void sing(){
            System.out.println("小鸟唱歌");
        }

        void display(){
            System.out.println(this.name);          //调用内部类的属性
            System.out.println(Person.this.name);   //调用外部类的结构
        }
    }
}

局部内部类

class A {

    // 局部内部类的使用
    // 返回一个实现了Comparable接口的类的对象
    public Comparable getComparable() {

        // 局部内部类
        class Mycomparable implements Comparable {

            @Override
            public int compareTo(Object o) {
                // TODO Auto-generated method stub
                return 0;
            }

        }

        return new Mycomparable();
    }
}
  • 在局部类中使用局部内部类所在方法中的局部变量时,要求局部变量是final的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值