mt_Day5:static与继承

static静态关键字

1.static成员变量

  • static + 成员变量:该变量在内存中只存储一份,可以被共享访问、修改
  • 静态成员变量的访问
public class User {
    /**
     * 例子:在线人数定义为静态成员变量
     */
    public static int onlineNumber=50;
    
    //实例成员变量
    private String name;
    private int age;
}
public class staticFieldDemo1 {
    public static void main(String[] args) {
        //1.用类名访问静态成员变量,推荐
        //User.onlineNumber
        System.out.println(User.onlineNumber);

        //2.用对象访问静态成员变量,不推荐
        User u=new User();
        System.out.println(u.onlineNumber);
    }
}

2.static成员变量的内存

存在堆内存

3.成员方法分类

  • 静态成员方法(无static修饰,归属于类),建议类名访问,也可以用对象访问
  • 实例成员方法(有static修饰,归属于对象),只能用对象触发访问

4.static成员方法内存

存在方法区

5.static访问注意事项

  • 静态方法只能访问静态成员,不能直接访问实例成员(可以创建对象间接访问实例成员)
  • 实例方法可以访问静态成员,也可以访问实例成员
  • 静态方法中不能出现this关键字(因为this是当前对象地址,静态方法可能是不由对象调用的)

工具类

无需创建对象,内部都是一些静态方法,每个方法完成一个功能

一次编写,处处可用,提高代码的重用性

//例子:生成验证码的重复类
public class util {
    /**
     * 工具类无需创建对象,所以将其构造器私有化
     */
    private util(){
    }
    //静态方法
    public static String creatCode(int n){
        String code="";
        String data="abcdefghijklmnopqrstyvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" +
                "1234567890";
        Random r=new Random();
        for (int i = 0; i < n; i++) {
            int index=r.nextInt(data.length());
            code+=data.charAt(index);
        }
        return code;
    }
}

代码块

  • 类的5大成分之一(成员变量、构造器、方法、代码块、内部类),定义在类中方法外
  • 在Java类中,用{}括起来的代码称为代码块

静态代码块:

  • 格式:static{}
  • 特点:用static关键字修饰,随着类的加载而加载,自动触发,只执行一次
  • 使用场景:在类加载时,做一些静态数据初始化操作,以便后续使用
public class staticCodeDemo1 {
    //静态资源,如城市名,一副扑克牌
    public static String city;
    public static ArrayList<String> cards=new ArrayList<>();
    //静态代码块
    static {
        //比main方法优先调用
        //作用:初始化静态资源
        System.out.println("静态代码块被执行了");
        city="北京";
    };
    public static void main(String[] args) {
        System.out.println("main方法被执行");
        System.out.println(city);
    }
}
/*
静态代码块被执行了
main方法被执行
北京
*/

构造(实例)代码块:(很少用)

  • 格式:{}
  • 特点:每次创建对象,调用构造器前,都会执行一次{}中的代码,在构造器执行前执行(顺序:父构造,实例代码块,子构造)
  • 使用场景:初始化实例资源
public class staticCodeDemo2 {
    private String name;
    staticCodeDemo2(){
        System.out.println("无参构造器被触发执行");
        name="张三";
    }
    //实例代码块
    {
        System.out.println("实例代码块被触发执行");
    }
    public static void main(String[] args) {
        staticCodeDemo2 a=new staticCodeDemo2();
        System.out.println(a.name);
    }
}
/**
 * 实例代码块被触发执行
 * 无参构造器被触发执行
 * 张三
 */

静态代码块案例:

扑克游戏需要一份扑克牌

  • 存储54张牌类对象的集合,静态的集合指挥家在一份
  • 系统启动同时准备好54张牌的数据,可用静态代码块完成
public class staticCodeTest3 {
    /**
     * 定义一个静态集合,因为当前房间只需要一副扑克牌
     */
    public static ArrayList<String> cards=new ArrayList<>();

    /**
     *main方法执行前,放入54张牌
     * 如果放在main中,若main调用很多次,static内容也会被执行多次,但在静态代码块只执行一次
     */
    static{
        //点数
        String[] sizes={"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
        //花色
        String[] colors={"♥","♠","♦","♣"};
        //组合
        for (int i = 0; i < sizes.length; i++) {
            for (int j = 0; j < colors.length; j++) {
                String card=sizes[i]+colors[j];
                cards.add(card);
            }
        }
        cards.add("大🃏");
        cards.add("小🃏");
    }
    public static void main(String[] args) {
        System.out.println("新牌:"+cards);
    }
}

单例模式

  • 保证系统中,应用该模式的这个类永远只有一个实例,即一个类只能创建一个对象
  • 例如:任务管理器对象只需要一个就可以解决问题,可以节省内存空间

饿汉单例

用类获取对象前,对象已经提前创建好

  • 定义一个类,构造器私有
  • 定义一个静态存储对象
public class singleInstence {
    /**
     * 使用饿汉单例来实现单例类
     * 饿汉单例:在获取对向前,对象已经提前准备好一个
     * 这个对象只能是一个,所以用静态成员变量记住
     */
    public static singleInstence hunger=new singleInstence();
    //因为对象只能有一个,构造器私有
    private singleInstence(){
        
    }
    public static void main(String[] args) {

    }
}
public class test1 {
    public static void main(String[] args) {
        singleInstence s1=singleInstence.hunger;
        singleInstence s2=singleInstence.hunger;
        System.out.println(s1==s2);//true
    }
}

懒汉单例

真正需要该对象的时候,才去创建一个对象(延迟加载对象),防止你在创建对象后没使用浪费内存,所以用时才创建

类加载的时候,懒汉的方法在方法区,并没有在栈内存;当调用懒汉的getInstance()方法得到对象时,才会进入栈内存,这样就节约了一部分内存

  • 第一个类,构造器私有
  • 定义一个静态变量存储对象
  • 提供一个返回单例对象的方法
public class singleInstace2 {
    /**
     * 懒汉单例
     */
    public static singleInstace2 lazy;//=new singleInstace2();×,用时才创建对象,lazy地址为null
    private singleInstace2(){

    }

    public static singleInstace2 returnlazy(){
        if(lazy==null){
            //第一次来拿对象:需要创建对象,即懒汉用时才创建
            lazy=new singleInstace2();
        }
        return lazy;
    }
}

继承

子类存储空间

一个子类对象分为父类空间和子类空间

继承的特点

  1. 子类继承父类的属性和行为,但不能继承父类的构造器
  2. Java是单继承模式,一个类只能继承一个父类
  3. Java不支持多继承,但支持多层继承
  4. Java中所有的类都是Object的子类

子类继承了父类的私有成员,但不能直接访问

子类可以访问父类的静态成员,但是以共享的形式,不算继承

多层继承,若方法重名,就近原则

继承后成员的访问特点

就近原则

public class test {
    public static void main(String[] args) {
        Dog d=new Dog();
        d.run();    //就近调用子类的run方法:狗也可以跑
    }
}
class Animal{
    public void run(){
        System.out.println("动物可以跑");
    }
}

class Dog extends Animal{
    public void run(){
        System.out.println("狗也可以跑");
    }
}

方法重写

子类中写一个与父类声明一样的方法,覆盖父类方法

@Override //重写校验注解,加上后,必须是正确重写,更安全

public class test {
    public static void main(String[] args) {
        newPhone p=new newPhone();
        p.call();//可以打电话 还可以视频通话
    }
}
class phone{
    public void call(){
        System.out.println("可以打电话");
    }
}
class newPhone extends phone{
    @Override   //重写校验注解,加上后,必须是正确重写,更安全
    public void call(){
        super.call();
        System.out.println("还可以视频通话");
    }
}

注意事项和要求

  • 重写方法的名称、形参列表与被重写方法的名称、形参列表一致
  • 私有方法不能重写
  • 子类重写父类方法时,访问权限必须大于或等于父类(缺省<protected<public)父:public void call() 子:private void call() 不可以重写
  • 子类不可以重写父类的静态方法

子类继承父类构造器特点

子类中所有的构造器,默认都会先访问父类中的无参构造器,再执行自己

因为

  • 子类在初始化的时候,有可能会使用到父类中的数据,如果父类没有完成初始化,子类将无法使用父类的数据
  • 子类初始化之前,一定要调用父类构造器完成父类数据空间的初始化,子类构造器前都默认有一个super()

子类构造器访问父类有参构造器

public class people {
    private String name;
    private int age;

    people(){

    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
public class teacher extends people{
    public teacher(String name,int age){
        //调用父类的参数构造器,初始化继承父类的数据
        super(name,age);
    }
}
public class test {
    public static void main(String[] args) {
        teacher t=new teacher("张三",30);
        System.out.println(t.getName());
        System.out.println(t.getAge());
    }
}

this关键字

例子:学生填写姓名、国籍信息,不填写国籍,国籍默认为中国

public class Student{
    private String name;
    private String nation;
    public Student(String name){
        this(name,"中国");
    }

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

this(…)与super(…)使用注意点

  • 子类通过this(…)调用本类的其他构造器,本类的其他构造器通过super手动调用父类的构造器,最终还是会调用父类的构造器
  • 注意:this(…),super(…)都只能放在构造器的第一行,二者不能共存在同一个构造器中
posted @ 2023-01-20 23:20  NIka_mt  阅读(29)  评论(0)    收藏  举报