Java 面向对象进阶

Java 面向对象进阶

面向对象知识学习建议

  • 多关注语法的基本作用和流程。
  • 多进行思考和语法记忆。
  • 自信,不要在短期想能做什么?

1. static 关键字

静态关键字

static的作用,修饰成员变量的用法

static关键字的作用

  • static是静态的意思,可以修饰成员变量,表示该成员变量只在内存中存储一份,可以被共享访问,修改

成员变量可以分成两类

  • 静态成员变量(有static修饰,属于类,内存中加载一次):常表示如在线人数信息,等需要被共享的信息,可以被共同访问。
public class User{
	//静态成员变量
	public static String onlineNumber = 160;
}


//访问方式
类名.静态成员变量(推荐)
对象.静态成员变量(不推荐)
  • 实例成员变量(无static修饰,存在于每一个对象中):常表示姓名name,年龄age,等属于每一个对象的信息。
public class User{
	//静态成员变量
	public static String onlineNumber = 160;
	//实例成员变量
	private String name;
	private int age;
	
}

//实例成员变量的调用方式
对象.成员变量
static修饰成员变量的内存原理

在这里插入图片描述

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

成员方法的分类

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

使用场景

  • 表示对象自己的行为的,且方法中需要访问实例成员的,则该方法必须声明成实例方法
  • 如果该方法是以执行一个通用功能为目的的,或者需要方便访问,则可以申明成静态方法。
public class Student {
    private String name;
    private  int age;

    /*
    * 实例方法:无static修饰,属于对象的,通常表示对象自己的行为,可以访问对象的成员变量
    *
    * */

    public void study(){
        System.out.println(name + "在好好学习!");
    }

    /**
     * 静态方法,有static修饰,属于类,可以被类和对象共享访问。
     *
     * */
    public static void getMax(int a, int b){
        System.out.println(a>b?a:b);
    }


    public static void main(String[] args) {
        //1.类名.静态方法
        Student.getMax(3, 5);
        //注意:同一个类中访问静态成员,可以省略类名不写
        getMax(3,4);

        //2.对象.实例方法
        //study();会报错,虽然study()实在类中定义的,但它属于对象的行为,无法直接调用
        Student student = new Student();
        student.name = "智者";
        student.study();     //输出:智者在好好学习!

        //不推荐使用方式
        student.getMax(1,2);   
    }
}
static修饰成员方法的内存原理

在这里插入图片描述

static实际应用案例:设计工具类

工具类:

  • 对于一些应用程序中多次需要用到的功能,可以将这些功能封装成静态方法,放在一个类中,这个类就是工具类。
  • 工具类的作用:一是方便调用,二是提高了代码复用

工具类原理和延申

  • 一次编写,处处可用
  • 建议将工具类的构造器私有,不让工具类对外产生对象。
//工具类
import java.util.Random;

public class Tools {
    //构造器私有化,工具类不需要产生对象,直接可以通过类进行调用,产生对象反而会占用内存
    private Tools(){
        
    }
    
    //定义创建验证码的静态方法
    public static String crateCode(int numbner){
        //定义变量存储验证码
        String verifyCode = "";
        //创建随机数对象
        Random r = new Random();

        String code = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

        //生成验证码
        for (int i = 0; i < numbner; i++) {
            int index = r.nextInt(code.length());
            verifyCode += code.charAt(index);
        }
        return verifyCode;
    }

}


//测试类
/**
 * 该类主要用于测试工具类中的静态方法的作用
 * */

public class LogIn {
    public static void main(String[] args) {
        //验证码
        System.out.println("验证码" + Tools.crateCode(5) );
    }

}

具体案例:

/**
 * 工具类案例:
 * 需求:在实际开发中,经常会遇到一些数组使用的工具类。请按照如下要求编写一个数组的工具类:ArraysUtils
 * 1.我们知道数组对象直接输出的时候是输出对象的地址,而项目中很多地方都需要返回数组的内容,请在
 * ArraysUtils中提供一个工具类方法toString,用于返回整数数组的内容,返回的字符串格式如:[10,20,50,34,100](只考虑整数数组,且只考虑一维数组)
 * 2.经常需要统计平均值,平均值为去掉最低分和最高分后的分值,请提供这样一个工具方法getAverage,用于返回平均分(只考虑浮点型数组,且只考虑一维数组)
 * 3.定义一个测试类TestDemo,调用该工具类的工具方法,并返回结果
 *
 *
 * */


//工具类
public class ArraysUtils {
    //构造器私有化
    private ArraysUtils(){

    }

    //定义工具类方法:用于返回整数数组的内容,返回的字符串格式如:[10,20,50,34,100](只考虑整数数组,且只考虑一维数组)
    public static String toString(int[] array){
        //定义返回值变量
        String str = "[";
        for (int i = 0; i < array.length; i++) {
            str += (i == array.length-1?array[i]:array[i]+",");
        }
        str += "]";
        return str;
    }

    //定义工具类方法,用于返回平均分
    public static double getAverage(double[] array){
        //定义变量存储平均值
        double avg = 0;
        //定义变量存储数组中的最大值
        double max = array[0];
        //定义变量存储数组中的最小值
        double min = array[0];
        //定义变量存储总和
        double sum = 0;

        //获取最值,总和
        //判断数组的长度是否大于2,以保证存在最高分与最低分
        if(array.length>2){
            for (int i = 0; i < array.length; i++) {
                max = max>array[i]?max:array[i];
                min = min<array[i]?min:array[i];
                sum += array[i];
            }
            //获取平均分
            avg = (sum-max-min)/(array.length-2);
        }else{
            for (int i = 0; i < array.length; i++) {
                sum += array[i];
            }
            avg = sum/array.length;
        }



        return avg;
    }

}

/**
 * 工具测试类
 *
 * */
public class TestDemo {
    public static void main(String[] args) {
        //定义两组数组,分别为整型和浮点型
        int[] arr = new int[]{1, 2, 4, 5, 3};
        double[] score = new double[]{98.2, 99.2, 89.5, 87.5};


        System.out.println("arr:" + ArraysUtils.toString(arr));
        System.out.println("该选手的平均分为:" + ArraysUtils.getAverage(score));
    }

}
static的注意事项总结(面试热点)
  • 静态方法只能访问静态成员,不可以直接访问实例成员
  • 实例方法可以访问静态成员,也可以访问实例成员。
  • 静态方法中是不可以出现this关键字

2. static 应用知识:代码块

代码块概述

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

代码块分为

  • 静态代码块

    • 格式:static{};

    • 特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发,只执行一次

    • 使用场景:在类加载的时候做一些静态数据初始化的操作,以便后续使用。

    • public class TestDemo{
          //定义静态变量
          public static schoolName;
          
          //定义主函数
          public static void main(String[] args){
              System.out.println("执行主函数")
          }
          
          //定义静态代码块
          static{
              //对静态成员变量进行初始化
              schoolName = "university";
              System.out.println("执行静态代码块");
              System.out.println(schoolName);
                 
          }    
          
      }
      
      //结果
      执行静态代码块
      university
      执行主函数
      
  • 构造代码块(了解,用的少)

    • 格式:{}
    • 特点:每次创建对象,调用构造器执行时,都会执行改代码块中的代码,并且在构造器执行前执行
    • 使用场景:初始化实例资源
public class TestDemo{
    //定义无参构造函数
    public TstDemo(){
        System.out.println("构造器被触发执行")}
    
    /*
    定义构造代码块
    */
    {
        System.out.println("构造代码块被触发执行")}
    
    public static void main(String[] args){
        System.out.println("主函数被调用执行")
        new TestDemo();   //创建匿名对象
        
}
    
//结果
主函数被调用执行
构造代码块被触发执行
构造器被触发执行

案例:斗地主游戏

案例:斗地主游戏
需求:在游戏开始阶段准备一副扑克牌
分析:
1.定义字符串集合存储扑克牌
2.利用静态代码块,在游戏开始前,输出扑克牌
import java.util.ArrayList;

/**
 * 案例:斗地主游戏
 * 需求:在游戏开始阶段准备一副扑克牌
 * 分析:
 * 1.定义字符串集合存储扑克牌
 * 2.利用静态代码块,在游戏开始前,输出扑克牌
 * */

public class Test1 {
    //成员方法
    public static ArrayList<String> array = new ArrayList<>();

    //无参构造方法
    public Test1(){}

    //利用静态代码块将扑克牌存储到集合中
    static{
        String[] arr1 = new String[]{"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};
        String[] arr2 = new String[]{"♥", "♠", "♦", "♣"};

        //产生每张牌的四种花色
        for (int i = 0; i < arr1.length; i++) {
            for (int i1 = 0; i1 < arr2.length; i1++) {
                Test1.array.add(arr2[i1] + arr1[i]);
            }
        }
        //在扑克牌中添加大小王
        array.add("大🃏");
        array.add("小🃏");

        //输出扑克牌
        System.out.println(array);
    }

    public static void main(String[] args) {
        System.out.println("开始游戏");
    }
}

3. 设计模式:单列

什么是设计模式

  • 设计模式是一套被前人反复使用,多=多数人知晓,经过分类编目的代码设计经验的总结,后来者可以直接拿来解决问题。
  • 设计模式是软件设计中的常见解决方案,好的设计模式可以进一步的提高代码的重用性。

单例模式

  • 可以保证系统中,应用该模式的类永远只有一个实例,即一个类永远只能创建一个对象。

单例的场景和作用

  • 例如任务管理器对象我们只需要一个就可以解决问题,这样可以节省内存空间。

单例的实现方式

  • 饿汉单例
  • 懒汉单例

饿汉单例

  • 在用类获取对象的时候,对象已经提前为你创建好了。

设计步骤

  • 定义一个类,把构造器私有化
  • 定义一个静态变量存储一个对象
//单例模式

public class SingleInstance {
    //构造器私有化
    private SingleInstance(){}

    //创建一个静态的对象
    public static SingleInstance instance = new SingleInstance();
}

//单例模式测试类
public class SingleInstanceDemo {
    public static void main(String[] args) {
        SingleInstance s1 = SingleInstance.instance;
        SingleInstance s2 = SingleInstance.instance;

        System.out.println(s1);
        System.out.println(s2);
        System.out.println(s1==s2);
    }
}

懒汉单例模式

  • 在真正需要该对象的时候,才去创建一个对象(延迟加载对象)。

设计步骤:

  • 定义一个类,把构造器私有化
  • 定义一个存储对象的静态变量(不初始化)
  • 提供一个返回单例对象的方法
//懒汉单例
public class SingleInstance2 {
    //1.构造器私有化,防止用户创建多个对象
    private SingleInstance2(){}

    //2.定义静态变量存储对象(不初始化)
    private static  SingleInstance2 instance2;

    //定义方法创建对象
    public static SingleInstance2 getInstance(){
        if(instance2 == null){
            instance2 = new SingleInstance2();
        }
        return instance2;
    }
}

//懒汉单例模式测试类

public class SingleInstance2Demo {
    public static void main(String[] args) {
        SingleInstance2 s1 = SingleInstance2.getInstance();
        SingleInstance2 s2 = SingleInstance2.getInstance();

        System.out.println(s1);
        System.out.println(s2);
        System.out.println(s1==s2);
    }
}

4.面向对象三大特征:继承

什么是继承

  • 继承是类与类之间的一种关系
  • 多个类继承单独的某个类,多个类就可使用单独的类的属性和行为
  • 多个类称为子类(派生类),单独的这个类称为父类(基类或超类)。

在这里插入图片描述

继承的格式

  • 在java中,继承用关键字"extends".

示例:

//人类
public class People {
    //成员变量
    private String name;
    private int age;

    //无参构造器
    public 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 Student1 extends People {
    //构造方法
    public Student1() {
    }

    public Student1(String name, int age) {
        super(name, age);
    }

    //定义学生类自己的方法
    public void study(){
        System.out.println("学生正在好好学习!");
    }
}

//老师类
public class Teacher extends People{
    //构造器
    public Teacher() {
    }

    public Teacher(String name, int age) {
        super(name, age);
    }

    //定义老师类的方法
    public void teach(){
        System.out.println("老师正在快乐的交java");
    }
}

总结:

  1. 什么是继承,继承的好处
    • 继承是子类到父类的一种关系
    • 提高代码的复用性,减少代码冗余,增强类的功能扩展性
  2. 继承的格式
    • 子类 extends 父类
  3. 继承后子类的特点
    • 子类继承父类,子列可以得到父类的属性与行为,子类可以使用。
    • 在Java中子类更强大

继承的规范

  • 子类相同特征(共同属性,共同方法)放在父类中定义,子类独有的属性和行为应定义在子类自己里面。

为什么?

  • 如果子类的独有属性,行为定义在父类,会导致其他的子类也会得到这些属性和行为,这不符合面向对象逻辑。

继承的内存原理

在这里插入图片描述

继承的特点

  • 子类可以继承父类的属性和行为,但是子类不能继承父类的构造器
  • Java是单继承模式:一个类只能继承一个直接父类。
  • Java不支持多继承,但支持多层继承
  • 在Java中所有的类都是Object类的子类

子类是否可以继承父类的静态成员

  • 有争议的知识点
  • 子类可以直接使用父类的静态成员(共享)
  • 单个人认为:子类不能继承父类的静态成员。(共享非继承)

在子类方法中访问成员(成员变量,成员方法)满足:就近原则

  • 先在子类局部范围找
  • 然后子类成员范围找
  • 最后父类成员范围找,如果父类范围还没有找到则报错

继承中的方法重写

什么是方法重写?

  • 在继承体系中,子类出现了和父类中一摸一样的方法声明,我们就称子类这个方法是重写的方法。

方法重写的应用场景

  • 当子类需要父类的功能,但父类的该功能不完全满足自己的需求时
  • 子类可以重写父类中的方法

@Override重写注解

  • @Override是放在重写后的方法上,作为重写是否正确的校验注解。
  • 加上该注解后如果重写错误,编译阶段会出现错误提示。
  • 建议重写方法都加上@Override注解,代码安全,优雅!

方法重写的注意事项和要求

  • 重写方法的名称,形参列表必须与被重写方法的名称和形参列表一致。
  • 私有方法不能被重写。
  • 子类重写父类方法时,访问权限必须大于或等于父类(暂时了解:缺省<protected<public
  • 子类不能重写父类的静态方法

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

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

为什么?

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

怎么调用父类构造器的?

  • 子类构造器的第一行语句默认都是:super(),不写也存在。

this和super详情

  • this:代表本类对象的引用;super:代表父类存储空间的标识。

在这里插入图片描述

注意事项

  • 子类通过this(…)去调用本类的其他构造器,本类其他构造器会通过super去手动调用父类的构造器,最终还是会调用父类构造器
  • 注意:this(…),super(…)都只能放在构造器的第一行,所以二者不能共同存在同一个构造器中。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值