Java面向对象static——学习笔记(8)

注意事项:

1、多关注语法点的基本作用

2、思考、记忆、练习

3、自信!不要想短期内做什么

一、static

1、是什么

static静态,修饰成员变量、成员方法。内存中只存储一份,可以共享访问、修改。

2、调用方法

2种,类名.静态成员变量(推荐);对象.静态成员变量(不推荐)。

3、区分静态成员变量和实例成员变量

静态成员变量,属于类的,直接用类名去调用,可以共享的信息;

实例成员变量,属于某个实例对象的,必须用实例名去调用,每个对象都不同的信息。

package com.laogao.staticdemo;

public class User {
    public  static int onLineNum=11;//内存中只一份
    private String name;
    private int age;//私有的,通过getter\setter去调用修改

    public static void main(String[] args) {
        //输出静态成员变量
        System.out.println(User.onLineNum);
        System.out.println(onLineNum);//在类中,可以直接用名称调用静态成员变量
        //创建实例对象
        User user=new User();
        user.onLineNum++;//调用静态成员变量
        System.out.println(user.onLineNum);//输出静态成员变量

        user.age=18;
        user.name="ll";
        System.out.println(user.age);//输出实例成员变量
    }
}

4、static修饰成员变量的内存原理

(1)首先是将 类 加载到方法区,同步在堆内存中开辟一块存储相应的静态变量区(加载静态变量)。

(2)提main方法到栈里,在下边堆内存这个图里,可以清晰的看出来,实例成员变量(name、age)是属于每个对象的,而静态成员变量(onLineNumber)是属于类的。

c87962ec6fff4b458d9f43ce7b7baa29.png

 看弹幕确实拓展了我的思考:

(1)用private,static还能共享吗?有个问题类似这样。

个人理解:static修饰的变量就是能共享、修改的,所以和前边的public、private没啥关系,public和private应该是该变量使用的范围吧,在本类里用,还是其他类也能用的问题。(不过static是共享的,那用private应该是没有必要的)

结合起来,大概就是public你按照调用的规范,想怎么用都行。private就有了限制,本类里用没什么问题,在类外边用或者通过对象调用这个静态成员变量就不行了,待验证

(2)静态成员变量和全局变量,动态变量与静态变量,待学习。

5、static修饰成员方法的基本用法

静态成员方法,共享,归属于类,可以用类、对象访问;在类中,可以直接用方法名调用(实际是用类去调用的这个静态方法);

实例成员方法,属于对象,必须用对象去调用。

区分:

什么时候用static:共用功能,和对象没什么关系。

什么时候不用static:需要访问实例成员时,对象自己的行为。

6、修饰成员方法的内存原理

分析:先在方法区加载静态方法,提main方法在栈中运行,如果main中调用了静态方法,直接去方法区找,提到栈中执行。如果调用的是实例成员方法,会先找到堆内存中的对象,再通过对象中的引用地址找到方法。

e216b0e5a51b419a8ff1eaea1d6b88f1.png

7、注意事项(面试笔试)

(1)静态方法只能访问静态成员,不可以直接访问实例成员(如果创建一个对象,那可以访问)。

(2)实例方法可以访问静态成员,也可以访问实例成员。静态成员是共享的,当然可以访问。实例方法、实例变量都是属于当前对象的,都是用对象去调用,因此实例方法可以直接访问实例成员 。

(3)静态方法中不可以出现this关键词。理解:this代表当前对象,静态方法可以用类调用,可以用对象调用。如果静态方法用类去调用,那方法中出现的this就找不到当前对象了;如果静态方法是用对象调用的,那么静态方法中可以出现this,但这谁也不能保证每次都用对象去调用。

二、static应用知识:工具类util

1、好处

调用方便(直接用类名调用,不需要创建对象),提高代码复用。

2、工具类

里边都是静态方法,让开发人员共同使用。

3、要求

建议将工具类构造器私有化(装B必备)。

工具类构造器私有化,这样就无法创建工具类对象了。要想访问工具类中的静态方法,直接用类名,不能创建实例对象。

4、代码练习

package com.laogao.staticdemo;

/**
 * 数组工具类
 */
public class ArrayUtil {
    /**
     * 构造器私有化
     */
    private ArrayUtil(){

    }

    /**
     * 输出整型数组
     * @param arr
     * @return
     */
    public static String toString(int [] arr) {
        //1、校验
        if (arr==null){
            return null;
        }
        String rs="[";
        for (int i = 0; i < arr.length; i++) {

            rs+=(i== arr.length-1?arr[i]:arr[i]+",");
        }
        rs+="]";
        return rs;
    }

    /**
     * 去掉最值,计算平均值
     * @param arr
     * @return
     */
    public static double getAerage(double[] arr){
        double max=arr[0],min=arr[0];
        double sum=arr[0];
        for (int i = 1; i < arr.length; i++) {
            if(arr[i]>max){
                max=arr[i];
            }
            if(arr[i]<min){
                min=arr[i];
            }

            sum+=arr[i];
        }
        return (sum-max-min)/(arr.length-2);
    }

}

三、static应用知识:代码块

代码块——类的五大成分之一(成员变量、方法、构造器、代码块、内部类),定义在类中方法外。

1、静态代码块

优先初始化静态资源,格式   static{}   ,与类一起优先加载一次,自动触发执行。比main方法先执行。

2、构造代码块(实例代码块,少见)

属于对象,格式{}  , 比构造器先执行,初始化实例资源(一般不用)。

package com.laogao.staticdemo;

public class StaticCode {

    /**
     * 静态代码块:初始化静态资源
     */
    static {
        System.out.println("调用静态代码块");
    }

    /**
     * 无参构造器
     */
    public StaticCode(){
        System.out.println("====调用无参构造器=====");
    }
    /**
     * 构造代码块,实例代码块,初始化实例资源
     * 一般不用,了解
     */
    {
        System.out.println("调用实例代码块");
    }

    public static void main(String[] args) {
        StaticCode staticCode=new StaticCode();
    }
}

运行结果: 

6bdaac7303814954addc819015a8bcd7.png

3、静态代码块应用案例

专业、优雅,只跑一次static{}  。

7fe50fd479254e4e95267e88e5603a86.png

package com.laogao.staticdemo;

import java.util.ArrayList;

public class StaticCode {

    //共享一副牌
    public static ArrayList<String> cardList=new ArrayList<>();
    /**
     * 静态代码块:初始化静态资源
     * 优先初始化静态资源,比main方法优先执行
     */
    static {
        System.out.println("调用静态代码块");
        //所有数字
        String[] nums={"2","3","4","5","6","7","8","9","J","K","A"};
        //所有花色
        String[] colors = {"♥", "♦", "♠", "♣"};
        //遍历添加到卡片列表
        for (int i = 0; i < nums.length; i++) {
            for (int j = 0; j < colors.length; j++) {
                String card=colors[j]+nums[i];
                cardList.add(card);
            }
        }
        cardList.add("大🃏");
        cardList.add("小🃏");
    }

    public static void main(String[] args) {
        System.out.println(cardList);
    }
}

 运行结果:

8231763bee3a42dbbb8b548fdf6a0238.png

四、static应用知识:单例设计模式

1、设计模式:即最优的解决方案

(1)单例模式:永远只有一个实例对象。可以节省内存空间。

(2)饿汉单例模式:获取对象前已经准备好了一个对象。

步骤:先构造器私有化,再用静态变量存储一个对象(静态变量属于类,只加载一次)。

package com.laogao.staticdemo;

public class SingleInstance {
    /**
     * 饿汉单例模式:提前已经准备好一个实例对象
     */
    //1、构造器私有化,不允许其他类创建本类对象
    private SingleInstance(){

    }
    //2、静态成员变量,存储实例对象;静态的是可共享的,那用public就行
    public static SingleInstance instance=new SingleInstance();

}
package com.laogao.staticdemo;

public class TestDemo {
    public static void main(String[] args) {
//        SingleInstance instance=new SingleInstance();//报错
        SingleInstance instance=SingleInstance.instance;//类名直接调用静态成员变量
        SingleInstance instance2=SingleInstance.instance;//类名直接调用静态成员变量
        System.out.println(instance==instance2);//true
    }
}

(3)懒汉单例模式:真正需要的时候,才去构建对象。

设计步骤:先构造器私有化,再定义一个静态成员变量负责存储一个对象,提供一个方法,返回单例对象。

package com.laogao.staticdemo;

public class SingleInstance {
    /**
     * 懒汉单例模式
     */
    //1、构造器私有化,不允许其他类创建本类对象
    private SingleInstance(){

    }
    //2、静态成员变量,存储实例对象;
    // 此处用private,这样获取对象只能通过类所提供的get方法进行获取,防止直接过去报错
    private static SingleInstance instance;
    //3、提供一个static方法,返回单例对象,这样可以直接通过类名调用该方法
    public static SingleInstance getInstance(){
        if (instance==null){//之开辟一块内存,节省空间
            instance=new SingleInstance();
        }
        return instance;
    }

}
package com.laogao.staticdemo;

public class TestDemo {
    public static void main(String[] args) {
//        SingleInstance instance=new SingleInstance();//报错
        SingleInstance instance=SingleInstance.getInstance();//类名直接调用静态成员变量
        SingleInstance instance2=SingleInstance.getInstance();//类名直接调用静态成员变量
        System.out.println(instance==instance2);//true
    }
}

五、继承

1、概述、好处

概述:extends,类和类之间存在的父子关系,子类可以使用父类(超类)中的属性和方法。

好处:提高代码复用性,减少代码冗余,增强类的功能扩展性(子类很多功能可以直接继承自父类)。

2、设计规范、内存原理

设计规范:子类间相同特征定义在父类中,独有的定义在子类中。

案例:2416c3a4816d4a7886c463f7021a4eaa.png

 父类:人


public class Student extends People{
    private String couse;

    public String getCouse() {
        return couse;
    }

    public void setCouse(String couse) {
        this.couse = couse;
    }

    public void listenFeedback(){
        System.out.println(getName()+"填写了听课反馈~");
    }
}

 子类:学生



public class Student extends People{
    private String couse;

    public String getCouse() {
        return couse;
    }

    public void setCouse(String couse) {
        this.couse = couse;
    }

    public void listenFeedback(){
        System.out.println(getName()+"填写了听课反馈~");
    }
}

子类:老师


public class Teacher extends People{
    private String department;

    public String getDepartment() {
        return department;
    }

    public void setDepartment(String department) {
        this.department = department;
    }

    public void questionPublic(){
        System.out.println(getName()+"老师,发布了问题~");
    }
}

测试类


public class TestDemo {
    public static void main(String[] args) {
        Student student=new Student();
        student.setName("张三");
        student.queryCouse();
        Teacher teacher =new Teacher();
        teacher.setName("李四");
        teacher.questionPublic();
    }
}

测试结果:

a78ac028fdee4282acb3efe044b1b6df.png

内存原理:

4a783a1657294d0195db674871cc5ccb.png

3、特点(面试)

(1)子类可以继承父类的属性和行为,但是子类不能继承父类的构造器

(2)java单继承模式,一个类只能继承一个直接父类

(3)Java不支持多继承、但支持多层继承

(4)Java中所有类都是Object类的子类

分析:

子类可以继承父类的私有成员,只是不能直接访问。

子类可以直接使用父类的静态成员(共享),但这应该不是继承。静态成员变量在内存中只有一份。

Object类是默认继承可以不写。

面试:为什么不支持多继承

加入两个父类中有相同的方法名,那用谁呢?Java是一种严谨的语言,不能有歧义

如果父类和父类的父类有相同方法,那就-->就近原则。

4、继承后:成员变量、成员方法的访问特点(笔试)

就近原则,先局部-->再子类成员变量-->再父类,找不到就报错。

(局部变量和成员变量重名情况下,如果一定要访问成员变量,可以加this;子类变量和父类变量重名情况下,如果一定要访问父类,加super)

5、继承后:方法重写

子类和父类的方法声明一样,在父类的某功能不能满足要求时,子类可以重写该功能。覆盖父类方法。

重写注解:加上@Oberride更优雅,告诉别人,这是一个重写的方法,如果报错说明这个方法没有重写成功。有重写校验的功能。更安全。

笔试:重写方法注意事项和要求

(1)重写的名字和形参列表必须一致!(这里可以回顾对比一下重载)

(2)私有方法不能被重写。

(3)子类重写父类方法时,访问权限必须大于或者等于父类(推荐写成和父类一致的权限,权限大小:缺省<protected<public)。

(4)子类不能重写父类的静态方法,如果重写会报错。(静态方法,整个类就这么共用一份)

6、继承后:子类构造器的特点

特点:子类先访问父类的无参构造器,在执行自己的构造器。

原因:可能会用到父类中的数据,因此先调用父类构造器初始化父类。

默认在子类构造器第一句是 super() ,调用父类无参数构造器。

7、继承后:子类构造器访问父类有参构造器

目的:将数据给父类有参构造器,初始化父类的一些数据。

super(参数……);//调用父类有参数构造器

调整窗口快捷方式:方便代码的编写 如下图:

a09a1b4c754348a9b143f4365ed2d5a2.png

注意事项:如果父类没有无参构造器,那会报错,因为子类默认调用父类的无参构造器。

解决办法:1、给父类写上无参构造器。2、子类中用super(参数……)调用父类有参数构造器。

8、this、super使用总结

479b14f0ec21444e9a3b30f70a0585c3.png

 练习:

教师类

package com.laogao.staticdemo;

public class Teacher extends People{
    private String department;
    private String label;
//无参数构造器
    public Teacher(){
        super();//默认
    }
//    有参构造器
    public Teacher(String department) {
        //调用其他构造器
        this(department,"公共课");//label默认Java
    }
    public Teacher(String department,String label){
        this.department=department;
        this.label=label;
    }
    public Teacher(String name, int age, String department) {
        super(name, age);
        this.department = department;
    }

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    public String getDepartment() {
        return department;
    }

    public void setDepartment(String department) {
        this.department = department;
    }

    public void questionPublic(){
        System.out.println(getName()+"老师,发布了问题~");
    }
}

测试类:

package com.laogao.staticdemo;

public class TestDemo {
    public static void main(String[] args) {
        Teacher teacher1=new Teacher();
        Teacher teacher2=new Teacher("计算机");
        Teacher teacher3=new Teacher("会计","审计");
        Teacher teacher4=new Teacher("李白",30,"传媒");
        System.out.println(teacher2.getLabel());
        System.out.println(teacher3.getLabel());
        System.out.println(teacher4.getAge());
    }
}

运行结果如下:

 

笔试:

子类通过   this(参数……)  去调用本类中的其他构造器。(一个类中可以有多个有参构造器,像方法重载,只是参数不同)

super()、this(参数……)  都要放在构造器的第一行,因此不能共同放在一个构造器中。

this(参数……)  在第一行时,将不再默认调用super(),而是通过this(参数……)先去找本类中的其他构造器,通过其他构造器再去默认调用父类构造器。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值