Java面向对象(下)--static/final/代码块/抽象/接口/内部类

目录

1 关键字:static

2 理解main方法的语法

3 类的成员之四:代码块

4关键字:final

5 抽象类与抽象方法

6 接口(interface)

7 类的成员之五:内部类

static

功能

  1. 含义:静态的

  2. 可以用来修饰属性、方法、代码块、内部类

  3. 使用static修饰属性:表示静态变量(类变量),没有static的为实例变量,如果创建了类的多个对象,多个对象共享同一个静态变量,当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时是修改过的

静态变量的其他说明:

  • 静态变量随着类的加载而加载,早于对象的创建,和类一样只会加载一次,在内存中存在一份
  • 可以通过类.静态变量的方式进行调用,而实例变量不能这样调用
  • 内存解析:
  1. 静态方法:类似静态变量,可以通过类之间调用,随着类加载,只能调用静态的方法或属性,对于非静态方法中,既可以调用非静态方法或属性,也可以调用静态方法或属性
  2. 注意点:
  • 静态的方法内,不能使用this关键字、super关键字
  • 关于静态属性和静态方法的使用,可以从生命周期的角度理解
  1. 开发中,如何确定一个属性是否要声明为static?
  • 如果属性是可以被多个对象所共享的,不会随着对象的不同而不同,如银行账户类中的利率属性

  • 类中的常量也常常声明为static

      开发中,如何确定一个属性是否要声明为static?
    
  • 操作静态属性的方法,通常设置为static

  • 工具类中的方法,习惯声明为static。比如Math、Arrays、Collections,不需要new对象即可直接用类调用方法

应用

class Circle{
    private double radius;
    private int id;
    
    public Circle(){
    	id=init++;//可以实现每次创建自动生成连续的id
   		total++;
	}
    public Circle(double radius){
    	this();//先调用一次上面的构造器,不用重复
        this.radius=radius;
	}
	private static int init=1001;
    private static total;
}

单例设计模式

采取一定的方法保证整个软件系统中某个类只存在一个对象实例,且该类只提供一个取得其对象实例的方法

饿汉式

public class SingletonTest1{
    public static void main(String[] args){
    Bank bank1=Bank.getInstance();    
    Bank bank2=Bank.getInstance(); //此时bank1==bank2成立   
    }
}
class Bank{
    //1.私有化类的构造器
    private Bank(){
        
    }
    //2.内部创建类的对象,要求此对象声明为静态
    private static Bank instance=new Bank();
    //3.提供公共方法,返回类的对象
    public static Bank getInstance(){
        return instance;
    }
}

懒汉式

public class SingletonTest1{
    public static void main(String[] args){
    Order order1=Bank.getInstance();    
    Order order2=Bank.getInstance(); //此时bank1==bank2成立   
    }
}
class Order{
    //1.私有化类的构造器
    private Order(){
        
    }
    //2.内部创建类的对象,要求此对象声明为静态
    private static Order instance=null;
    //3.提供公共方法,返回类的对象
    public static Order getInstance(){
        if(instance==null){
            instance=new Order();
        }
        return instance;
    }
}

区分饿汉式和懒汉式

饿汉式:对象加载时间过长(缺点),是线程安全的(优点)

懒汉式:延迟对象的创建(优点),目前的写法线程不安全,多线程内容时可以修改

使用场景

只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多资源时,可以直接产生一个单例对象,永久驻留内存

  1. 网站计数器,为了保证同步
  2. 应用程序的日志应用,因为日志文件一般一直处于打开操作,便于追加
  3. 数据库连接池,一个池子可以同时进行n个连接, 连接池固定一个
  4. 读取配置文件的类
  5. Application类
  6. windows任务管理器、回收站等

理解main方法的使用

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

类的成员四:代码块

相当于对属性赋值多了一种方式,实际上使用频率不高

  1. 代码块作用:用于初始化类、对象
  2. 代码块如果有修饰,只能使用static
  3. 分类:静态代码块 非静态代码块
  4. 静态代码块:
  • 内部可以有输出语句
  • 随着类的加载而执行;
  • 用于初始化类的信息;
  • 如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行;
  • 静态代码块的执行要优先于非静态代码块的执行
  1. 非静态代码块:
  • 内部可以有输出语句
  • 随着对象的创建(new)而执行
  • 每创建一个对象就执行一次
  • 作用是可以在创建对象时,对对象的属性等进行初始化
  • 如果一个类中定义了多个非静态代码块,则按照声明先后顺序执行
  1. 属性赋值的执行顺序

默认初始化--显式初始化/代码块中赋值--构造器中初始化--对象.属性或对象.方法赋值

final关键字

  1. final可以修饰的结构:类、方法、变量
  2. final类:此类不能被其他类继承,如String、System、StringBuffer
  3. final方法:不允许被重写,比如Object中getClass
  4. final变量:此时的变量称为是一个常量,不允许改变
  • 允许的赋值位置有:显示初始化,代码块中初始化、构造器中初始化
  1. final局部变量:尤其是使用final修饰形参时,表明此形参是常量,调用此方法时给该形参赋值,之后方法中只能使用不能重新赋值
  2. static final修饰属性:全局常量,接口中属性全是全局常量
  3. 用途:一般方法不常使用,属性有时需要final

抽象类与抽象方法

abstract意为抽象的,用来修饰结构、类、方法

抽象类

abstract修饰类:抽象类,此类不能实例化

  • 抽象类中一定有构造器,便于子类实例化时调用
  • 一般开发中都会提供子类

抽象方法

  • 只有方法的声明,没有方法体
  • 包含抽象方法的类必须是抽象类,但抽象类中可以没有抽象方法
  • 若子类重写了父类所有抽象方法后,子类方可实例化
abstract class Person{
    public abstract void eat();
}

使用上的注意点

  • abstract不能用来修饰属性、构造器等结构
  • 不能用来修饰私有方法、静态方法、final方法

创建抽象类的匿名子类

//Person定义为抽象类,Worker/Student为Person的子类
Worker worker=new Worker();
method(worker);//非匿名类非匿名对象

method(new Student()); //非匿名类匿名对象

//创建了一各匿名子类的非匿名对象:p
Person p=new Person(){
    @override
    public void eat(){//抽象类的子类必须重写其中的抽象方法
        
    }
} 
//创建匿名子类的匿名对象
method(new Person(){
    @override
    public void eat(){//抽象类的子类必须重写其中的抽象方法
        
    }
})

模板方法设计模式

public class TemplateTest{
    SubTemplate t=new SubTemplate();
    t.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(){
		System.out.println("sss");
        })
    }
}

接口

  • 有时需要从几个类派生出一个子类,java不支持多重继承,类无法满足这个条件。
  • 有时需要从几个类提取共同行为特征,但又没有is-a关系,只是有相同的行为特征。如大学生中学生都是学生,跨栏运动员篮球运动员都是运动员,他们都具有学习的技能,一方面他们已经有父类,另一方面他们与技能不满足子父类关系,因此可以把技能定义为接口

接口的使用

  1. 接口使用interface来定义

  2. java中,接口和类是并列的两个结构

  3. 如何定义接口:定义接口中的成员

    3.1 JDK7及以前:接口中只能定义全局常量和抽象方法

    全局常量:public static final(即使省略这几个词依然是全局常量)

    抽象方法:public abstract(即使省略这几个词依然是抽象方法)

    接口中不能定义构造器!!意味着接口不可以实例化

    3.2 JDK8以后 除了全局常量和抽象方法还可以定义静态方法和默认方法

  4. Java开发中,接口通过让类去实现(Implements)的方法来使用

    如果实现类重写了接口中所有抽象方法,则此实现类可以实例化

    如果没有覆盖所有抽象方法,则此实现类仍为抽象类

  5. java类可以实现多个接口,打破了类的单继承性的局限性,多个接口用implements A,B即可

  6. 接口与接口间可以继承,且可以多继承

  7. 接口的具体使用体现的多态性,接口实际上可以看做一种规范

package com.atguigu.ex1;

public class test {
	 
}
interface Flyable{
	public static final int MAX_SPEED=7900;
	int MIN_SPEED=7900;
	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 class Kite implements Flyable{
	@Override
	public void fly() {
		// TODO Auto-generated method stub
		
	}
}
//接口间多继承
interface AA{
	
}
interface BB{
	
}
interface CC extends AA,BB{
	
}

代理模式

应用场景:

安全代理:屏蔽对真实角色的直接访问

远程代理:通过代理类处理远程方法调用

延迟加载:先加载轻量级代理对象,需要再加载真实对象

分类:

静态代理

动态代理

工厂设计模式

实现了创建者与调用者的分离,即将创建对象的具体过程屏蔽起来,达到提高灵活性的目的

简单工厂模式,定义一个实现类对象的工厂类XXXFactory,包含getXXX等功能但是增加产品时需要对现有代码进行修改,违反了开闭原则

工厂方法模式,定义一个工厂接口,N个工厂类实现工厂接口,即可

Java8接口新特性

除了定义全局常量和抽象方法以外,还可以定义静态方法、默认方法

静态方法

1.接口中定义的静态方法,只能通过接口调用

2.通过实现类的对象,可以调用接口中的默认方法

3.如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的方法,那么子类没重写时,默认调用父类该方法(类优先原则)
但属性不允许重名

4.如果实现类实现了多个接口,而多个接口中定义了同名同参数默认方法,那么实现类没有重写此方法时报错(接口冲突),这就需要在实现类中重写此方法

public class SubclassTest {
	public static void main(String[] args) {
		Subclass s=new Subclass();
		//s.method1(); 接口的实现类调用会报错
		//1.接口中定义的静态方法,只能通过接口调用
		CompareA.method1();
		//2.通过实现类的对象,可以调用接口中的默认方法
		s.method2();
		s.method3();
	}
}
package com.atguigu.ex1;
public interface CompareA{
	public static void method1() {
		System.out.println("method1");
	}
	public default void method2() {
		System.out.println("method1");
	}
	default void method3() {
		System.out.println("method1");
	}
}

内部类

一个类定义于另一个类的内部,称为内部类,反之为外部类

  1. 内部类一般用在定义它的类或语句块内,外部引用时必须给出完整的名称
  2. 内部类分类:成员内部类(静态、非静态) 局部内部类(方法内、代码块内、构造器内)
  3. 成员内部类:可以调用外部类的结构;可以定义属性、方法、构造器等;可以被final、abstract修饰

关注三个问题:

  1. 如何实例化成员内部类的对象
		//创建Brain实例 静态的成员内部类
		Person.Brain br=new Person.Brain();
		//创建Eye实例 非静态的成员内部类
		Person person=new Person();
		Person.Eye eye=person.new Eye();
  1. 如何在成员内部类中区分调用外部类的结构

如果Person有内部类Brain,都定义了name属性,且Brain中有个方法形参为name,则

name 形参

this.name Brain类中的

Person.name Person中的

  1. 开发中局部内部类的使用

面试题:抽象类与接口异同

相同点:

  • 不能实例化
  • 都可以被继承

不同点:

  • 抽象类有构造器,接口不能声明构造器
  • 抽象类只能单继承,接口可以多继承
posted @ 2021-11-28 16:11  清梨  阅读(47)  评论(0编辑  收藏  举报