面向对象(四)
static的运用——单例模式
定义: 对某个类只能存在一个对象实例
分类: 饿汉式、懒汉式
一般步骤:
- 构造器私有化→防止直接new
- 类的内部创建对象
- 向外暴露实例的一个静态方法
//饿汉式
class Bank{
//1.私有化类的构造器
private Bank( ){}
//2.内部创建类的对象
//4.要求此对象也必须声明为静态的
private static Bank instance = new Bank( );
//3.提供公共的静态的方法,返回类的对象
public static Bank getInstance(){
return instance;
}
}
//懒汉式
class Order{
//1.私有化类的构造器
private Order(){}
//2.声明当前类对象,没有初始化//4.此对象也必须声明为static的
private static Order instance=null;
// 3.声明public、 static的返回当前类对象的方法
public static Order getInstance(){
if(instance==null){
instance=new Order();
}
return instance;
}
}
饿汉式和懒汉式的区别
- 创建对象的时机不同,饿汉式在类加载时创建,懒汉式在使用时加载。
- 饿汉式不存在线程安全问题,懒汉式存在线程安全问题
- 饿汉式可能存在浪费资源的可能
类成员——代码块
作用:用来初始化类、对象
结构:【修饰符】{代码}
特点:
- 不能通过对象或类显示调用,而是在加载类或创建对象时隐式调用
- 如果加了static,则属于静态代码块,静态代码块随着类的加载而执行,并且只执行一次,而普通代码块每创建一个对象都会执行。
- 如果只是使用类的静态成员,普通代码块并不会执行
分类:静态代码块和非静态代码块(根据是否有static修饰) - 静态代码块的使用
- 内部可以有输出语句
- 随着类的加载而执行,而且只执行一次
- 作用:初始化类的信息
- 如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
- 静态代码块的执行要优先于非静态
- 非静态代码块的使用
- 内部可以有输出语句
- 随着对象的创建而执行
- 每创建一个对象,就执行一次非静态代码块
- 作用:可以在创建对象时,对对象的属性等进行初始化
内部类
在Java中我们可以将类A声明在另一个类B中,这时类A被称为内部类,类B称为外部类。
分类:
- 定义在外部类的局部位置上
- 局部内部类
- 局部内部类使用和局部变量类似,不能加修饰符,可以使用final。
- 可以访问外部类的所有成员(包括私有的)
- 外部类访问:需要创建内部类的对象
- 匿名内部类
- 局部内部类
- 定义在外部类的成员位置上
- 成员内部类
成员内部类一方面,作为外部类的成员:
调用外部类的结构>可以被static修饰>可以被4种不同的权限修饰
另一方面,作为一个类:
类内可以定义属性、方法、构造器等;可以被final修饰,表示此类不能被继承。所以不使用final,就可以被继承;可以被abstract修饰。 - 静态内部类(使用static修饰)
- 成员内部类
public class Main{
public static void main(String[] args) {
Person1 p=new Person1();
Person1.Man man=p.new Man();//针对非静态内部类的实例化方式。
Person1.Women women=new Person1.Women();//静态内部类的实例化方式
man.show();//内部类方法的调用
women.show();//内部类方法的调用
}
}
class Person1 {
String name="1";
int age;
class Man{
String name="2";
int age;
public void show(){
System.out.println(name);//输出2,调用内部类的属性
System.out.println(this.name);//输出2,调用内部类的属性
System.out.println(Person1.this.name);//输出1,调用外部类的属性
}
}
static class Women{
String name="3";
int age;
public void show(){
System.out.println(name);//输出3,调用内部类的属性
System.out.println(this.name);//输出3,调用内部类的属性
//System.out.println(Person1.this.name);这个会编译报错java: 无法从静态上下文中引用非静态 变量 this
}
}
}
抽象类
定义:当父类的某些方法,需要声明,但又不确定如何实现时,可以声明为抽象方法,对应的类是抽象类
特点:
- 抽象类不可实例化
- 一个类中只要有抽象方法,则必须声明为抽象类
- 抽象方法不可以有主体
- 继承抽象类的子类必须实现抽象类中的所有抽象方法。 (除非子类也是抽象类)
- 抽象方法不可用private、final和static修饰
接口(interface)
为什么要有接口?
对Java单继承机制的补充
与抽象类的区别
- 接口中的所有方法都没有方法体(JDK 7)
- 接口中可以有静态方法和默认方法(JDK 8)
特点
- 接口不可以实例化
- 接口中所有方法都是public,抽象方法可以省略关键字abstract
- 普通类实现接口,必须实现所有方法,抽象类可以不实现
- 一个类可以实现多个接口
- 接口中的属性,只能是final. 也就是必须初始化
- 接口属性访问方式:接口名.属性名
- 接口不可以继承其他类,但可以继承多个别的接口。 (接口只 能说继承另一个接口,不能说实现另一个接口)
- 接口存在“多态传递”现象
// 多态与多态传递
// 有接口A和B B extends A 类 T implements B
B b=new T(); // 体现多态
A a=new T(); // 体现多态传递
定义接口
因为接口和类是并列的结构,所以定义方式类似。不过因为JDK7.0的更新,使得接口不止能够定义全局变量和抽象方法,还可以定义静态方法和默认方法。
全局变量格式:(public static final)类型 变量名 = 赋值 括号内的在书写时可以省略。
抽象方法格式:public abstract 方法名(){方法体}
使用事项:
- 接口中不可以定义构造器,也就意味着接口不可以被实例化
- Java开发中,接口通过让类去实现(implements)的方式来使用
如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化
如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类 - Java中一个类可以实现多个接口,这弥补了Java单继承的缺陷。
- 接口与接口之间可以继承,而且可以多继承。
- 接口的使用,体现了Java特性的多态性。
package com.psx;
/**
* @author psx
* @date 2021/2/1 9:18
*/
public class Main {
public static void main(String[] args) {
Person1 p=new Person1();
p.eat();
p.talk();
Dog.show();
System.out.println(Dog.a);
}
}
class Person1 implements Dog{
String name="1";
int age;
@Override
public void eat() {
System.out.println("吃饭了");
}
}
interface Dog{
public static final int a = 10; //全局变量
public abstract void eat(); //抽象方法
public default void talk(){ //默认方法
System.out.println("汪汪汪");
}
public static void show(){ //静态方法
System.out.println("这是一只狗");
}
}
public class Main{
public static void main(String[] args) {
Ball ball=new Ball("paiqiu");
ball.play();
}
}
interface Playable {
void play();
}
interface Bounceable {
void play();
}
interface Rollable extends Playable,Bounceable {
Ball ball = new Ball( "PingPang" );
}
class Ball implements Rollable {
private String name;
public String getName() {
return name;
}
public Ball(String name) {
this.name = name;
}
public void play() {
ball = new Ball("Football");//运行报错,ball在Rollable 接口中
///已经成为final属性了
System.out.println(ball.getName());
}
}
interface A {
int x= 0;
}
class B {
int x = 1;
}
class c extends B implements A {
public void pX() {
//System.out.println(x) ;报错,x指代不明确
System.out.println(super.x);//调用父类的属性
System.out.println(A.x);//调用接口的属性
}
public static void main(String[]args) {
new c().pX();
}
}
类变量
定义:定义在类中的静态变量
特点:
- 该变量被该类的所有实例共享
- 在类加载时就生成了,随类消亡而销毁
类方法
实质就是静态方法。一般用于工具类中
特点:
- 类方法和普通方法一样随类的加载而加载。(注:类方法没有this)
- 类方法可以通过类名或对象名调用
- 类方法只能访问静态变量或静态方法
类加载的时机
- 创建对象实例时(new)
- 创建子类对象实例时,对应的父类也会加载
- 使用类的静态成员时
创建对象时的调用顺序
- 静态代码块、静态属性初始化 (两者优先级相同)
- 普通代码块、普通属性的初始化
- 构造方法
创建子类对象时的调用顺序
- 父类静态代码块、静态属性
- 子类静态代码块、静态属性
- 父类普通代码块、普通属性
- 父类构造器
- 子类普通代码块、普通属性
- 子类构造器