7

Java基础知识(建议收藏)

 3 years ago
source link: https://blog.csdn.net/weixin_45860674/article/details/119547490
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

该篇为学习java整理的有关基础知识的笔记。
大部分源自于以下链接P1~P214:
https://www.bilibili.com/video/BV1uJ411k7wy?p=1
感谢此老师倾囊相授
下一篇Java进阶知识01链接:https://blog.csdn.net/weixin_45860674/article/details/119650957

1 MS-DOS命令提示符

2 IDEA快捷键

3 JAVA开发环境

3.1 JVM

JVM(Java Virtual Machine ):Java虚拟机,简称JVM,是运行所有Java程序的假想计算机,是Java程序的 运行环境,是Java 最具吸引力的特性之一。我们编写的Java代码,都运行在 JVM 之上。

跨平台:任何软件的运行,都必须要运行在操作系统之上,而我们用Java编写的软件可以运行在任何的操作系 统上,这个特性称为Java语言的跨平台特性。该特性是由JVM实现的,我们编写的程序运行在JVM上,而JVM 运行在操作系统上。

如图,JAVA虚拟机本身不具备跨平台的功能,每个操作系统下都有不同版本的虚拟机

3.2 JRE和JDK

JRE (Java Runtime Environment) :是Java程序的运行时环境,包含 JVM 和运行时所需要的 核心类库 。

JDK (Java Development Kit):是Java程序开发工具包,包含 JRE 和开发人员使用的工具。

我们想要运行一个已有的Java程序,那么只需安装 JRE 即可。

我们想要开发一个全新的Java程序,那么必须安装 JDK 。

三者关系: JDK > JRE > JVM

4 JAVA基本知识

4.1 数据类型分类

Java的数据类型分为两大类:

基本数据类型:包括 整数 、 浮点数 、 字符 、 布尔 。

引用数据类型:包括 类 、 数组 、 接口 。

四类八种基本数据类型:

4.2 数据类型转换

范围小的类型向范围大的类型提升

byte、short、char‐‐>int‐‐>long‐‐>float‐‐>double

4.3 JAVA虚拟机内存划分

数组就是存储数据长度固定的容器,保证多个数据的数据类型要一致。

5.1 格式

  1. 数组存储的数据类型[] 数组名字 = new 数组存储的数据类型[长度];
  2. 数据类型[] 数组名 = new 数据类型[]{元素1,元素2,元素3…};
  3. 数据类型[] 数组名 = {元素1,元素2,元素3…} ;

5.2 注意事项

  1. 不能越界,否则报错
  2. 数组空指针异常

5.3 数组作为方法参数和返回值

  1. 数组作为方法参数传递,传递的参数是数组内存的地址。
  2. 数组作为方法的返回值,返回的是数组的内存地址
  1. 定义类:就是定义类的成员,包括成员变量和成员方法。
  2. 成员变量:和以前定义变量几乎是一样的。只不过位置发生了改变。在类中,方法外。
  3. 成员方法:和以前定义方法几乎是一样的。只不过把static去掉。

6.1 成员变量默认值

6.2 一个对象的内存图

6.3 两个对象使用同一个方法内存图

6.4 两个引用指向同一个对象的内存图

6.5 成员变量和局部变量区别

在类中的位置不同

  1. 成员变量:类中,方法外
  2. 局部变量:方法中或者方法声明上(形式参数)

作用范围不一样

  1. 成员变量:类中
  2. 局部变量:方法中

初始化值的不同

  1. 成员变量:有默认值
  2. 局部变量:没有默认值。必须先定义,赋值,最后使用

在内存中的位置不同

  1. 成员变量:堆内存
  2. 局部变量:栈内存

生命周期不同 了解

  1. 成员变量:随着对象的创建而存在,随着对象的消失而消失
  2. 局部变量:随着方法的调用而存在,随着方法的调用完毕而消失

将属性隐藏起来,若需要访问某个属性,提供公共方法对其访问。

7.1 步骤

  1. 使用 private 关键字来修饰成员变量。 被private修饰后的成员变量和成员方法,只在本类中才能访问。
  2. 对需要访问的成员变量,提供对应的一对 getXxx 方法 、 setXxx 方法。

7.2 封装优化

7.2.1 this

this代表所在类的当前对象的引用(地址值),即对象自己的引用。

记住 :方法被哪个对象调用,方法中的this就代表那个对象。即谁在调用,this就代表谁。

7.2.2 构造方法

当一个对象被创建时候,构造方法用来初始化该对象,给对象的成员变量赋初始值。

无论你与否自定义构造方法,所有的类都有构造方法,因为Java自动提供了一个无参数构造方法, 一旦自己定义了构造方法,Java自动提供的默认无参数构造方法就会失效。

一个例子:

public class Student {
    private String name;
    private int age;
    // 无参数构造方法
    public Student() {}
    // 有参数构造方法
    public Student(String name,int age) {
        this.name = name;
        this.age = age;
    }
}

注意事项:

  1. 如果你不提供构造方法,系统会给出无参数构造方法。
  2. 如果你提供了构造方法,系统将不再提供无参数构造方法。
  3. 构造方法是可以重载的,既可以定义参数,也可以不定义参数。

7.3 标准规范JavaBean

public class ClassName{
    //成员变量
    //构造方法
    //无参构造方法【必须】
    //有参构造方法【建议】
    //成员方法
    //getXxx()
    //setXxx()
}

API(Application Programming Interface),应用程序编程接口

9 Scanner类

一个可以解析基本类型和字符串的简单文本扫描器。 例如,以下代码使用户能够从 System.in 中读取一个数。

System.in 系统输入指的是通过键盘录入数据。

9.1 使用步骤

import java.util.Scanner;

Scanner sc = new Scanner(System.in);

int i = sc.nextInt(); // 接收一个键盘录入的整数

10 匿名对象

创建对象时,只有创建对象的语句,却没有把对象地址值赋值给某个变量。

  1. 创建匿名对象直接调用方法,没有变量名。
  2. 一旦调用两次方法,就是创建了两个对象,造成浪费。
  3. 匿名对象可以作为方法的参数返回值

11 Random类

此类的实例用于生成伪随机数。

11.1 使用步骤

import java.util.Random;

Random r = new Random();

11.2 成员方法

public int nextInt(int n) :返回一个伪随机数,范围在 0 (包括)和 指定值 n (不包括)之间的 int 值。

12 ArrayList类

数组的长度是固定的,无法适应数据变化的需 求。为了解决这个问题,Java提供了另一个容器 java.util.ArrayList 集合类,让我们可以更便捷的存储和操作对象数据。

java.util.ArrayList 是大小可变的数组的实现,存储在内的数据称为元素。此类提供一些方法来操作内部存储 的元素。 ArrayList 中可不断添加元素,其大小也自动增长。

12.1 使用方法

import java.util.ArrayList;

ArrayList list = new ArrayList<>();

12.2 成员方法

  1. public boolean add(E e) :将指定的元素添加到此集合的尾部。
  2. public E remove(int index) :移除此集合中指定位置上的元素。返回被删除的元素。
  3. public E get(int index) :返回此集合中指定位置上的元素。返回获取的元素。
  4. public int size() :返回此集合中的元素数。遍历集合时,可以控制索引范围,防止越界。

12.3 如何存储基本数据类型

ArrayList对象不能存储基本类型,只能存储引用类型的数据。类似 不能写,但是存储基本数据类型对应的 包装类型是可以的。

基本类型基本类型包装类byteByteshortShortintIntegerlongLongfloatFloatdoubleDoublecharCharacterbooleanBoolean

13 String类

13.1 特点

  1. 字符串不变:字符串的值在创建后不能被更改。
  2. 因为String对象是不可变的,所以它们可以被共享。
  3. “abc” 等效于 char[] data={ ‘a’ , ‘b’ , ‘c’ } 。

13.2 构造方法

  1. public String() :初始化新创建的 String对象,以使其表示空字符序列。
  2. public String(char[] value) :通过当前参数中的字符数组来构造新的String。
  3. public String(byte[] bytes) :通过使用平台的默认字符集解码当前参数中的字节数组来构造新的 String。

13.3 常用方法

以下两种都返回布尔值:

  1. public boolean equals (Object anObject) :将此字符串与指定对象进行比较。
  2. public boolean equalsIgnoreCase (String anotherString) :将此字符串与指定对象进行比较,忽略大小写。

*equals方法:推荐常量写前面,变量写后面,例如:“abc”.equals(str1) ,因为str1为空倒过来回报错

13.4 常用功能方法

  1. public int length () :返回此字符串的长度。
  2. public String concat (String str) :将指定的字符串连接到该字符串的末尾。
  3. public char charAt (int index) :返回指定索引处的 char值。
  4. public int indexOf (String str) :返回指定子字符串第一次出现在该字符串内的索引。
  5. public String substring (int beginIndex) :返回一个子字符串,从beginIndex开始截取字符串到字符 串结尾。
  6. public String substring (int beginIndex, int endIndex) :返回一个子字符串,从beginIndex到 endIndex截取字符串。含beginIndex,不含endIndex。

13.5 转换功能方法

  1. public char[] toCharArray () :将此字符串转换为新的字符数组。
  2. public byte[] getBytes () :使用平台的默认字符集将该 String编码转换为新的字节数组。
  3. public String replace (CharSequence target, CharSequence replacement) :将与target匹配的字符串使 用replacement字符串替换。

13.6 分割功能方法

public String[] split(String regex) :将此字符串按照给定的regex(规则)拆分为字符串数组。

*split方法:如果用.切分则需要写 " \ \ ."

13.7 内存图

1、对于引用类型来说,==进行的是地址值的比较。
2、双引号直接写的字符串在常量池当中,new的不在池当中。

14 Static关键字

推荐用类名调用静态方法,不推荐用对象名调用

14.1 类变量(一个例子)

当 static 修饰成员变量时,该变量称为类变量。该类的每个对象都共享同一个类变量的值。任何对象都可以更改 该类变量的值,但也可以在不创建该类的对象的情况下对类变量进行操作

public class Student {
    private String name;
    private int age;
    // 学生的id
    private int sid;
    // 类变量,记录学生数量,分配学号
    public static int numberOfStudent = 0;
    public Student(String name, int age){
        this.name = name;
        this.age = age;
        // 通过 numberOfStudent 给学生分配学号
        this.sid = ++numberOfStudent;
    }
    // 打印属性值
    public void show() {
        System.out.println("Student : name=" + name + ", age=" + age + ", sid=" + sid );
    }
}
public class StuDemo {
    public static void main(String[] args) {
        Student s1 = new Student("张三", 23);
        Student s2 = new Student("李四", 24);
        Student s3 = new Student("王五", 25);
        Student s4 = new Student("赵六", 26);
        s1.show(); // Student : name=张三, age=23, sid=1
        s2.show(); // Student : name=李四, age=24, sid=2
        s3.show(); // Student : name=王五, age=25, sid=3
        s4.show(); // Student : name=赵六, age=26, sid=4
    }
}

14.2 静态方法

当 static 修饰成员方法时,该方法称为类方法 。静态方法在声明中有 static ,建议使用类名来调用,而不需要创建类的对象。调用方式非常简单。

注意事项:

  1. 静态方法可以直接访问类变量和静态方法
  2. 静态方法不能直接访问普通成员变量或成员方法。反之,成员方法可以直接访问类变量或静态方法。 静态方法只能访问静态成员。
  3. 静态方法中,不能使用this关键字。

14.3 内存图

静态代码块:

15 Array类

java.util.Arrays 此类包含用来操作数组的各种方法,比如排序和搜索等。其所有方法均为静态方法,调用起来 非常简单。

15.1 操作数组的方法

  1. public static String toString(int[] a) :返回指定数组内容的字符串表示形式。
  2. public static void sort(int[] a) :对指定的 int 型数组按数字升序进行排序。

16 Math类

java.lang.Math 类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数。类似这样的工具 类,其所有方法均为静态方法,并且不会创建对象,调用起来非常简单。

16.1 基本运算方法

  1. public static double abs(double a) :返回 double 值的绝对值。
  2. public static double ceil(double a) :返回大于等于参数的最小的整数。
  3. public static double floor(double a) :返回小于等于参数最大的整数。
  4. public static long round(double a) :返回最接近参数的 long。(相当于四舍五入方法)

直接通过子类对象访问成员变量(num):等号左边是谁,就优先用谁,没有则向上找。

间接通过成员方法访问成员变量(methodFu() methodZi()):该方法属于谁,就优先用谁,没有则向上找。

在父子类的继承关系当中,创建子类对象,访问成员方法(method())的规则:创建的对象是谁,就优先用谁,如果没有则向上找。

17.1 重写

重写(Override):方法的名称一样,参数列表【也一样】。覆盖、覆写。

重载(Overload):方法的名称一样,参数列表【不一样】。

Tips:重写的时候用上@Override 会有系统检查,避免小手一抖写错重写

注意事项:

方法覆盖重写的注意事项:

  1. 必须保证父子类之间方法的名称相同,参数列表也相同。
    @Override:写在方法前面,用来检测是不是有效的正确覆盖重写。这个注解就算不写,只要满足要求,也是正确的方法覆盖重写。

  2. 子类方法的返回值必须【小于等于】父类方法的返回值范围。
    小扩展提示:java.Lang . Object类是所有类的公共最高父类(祖宗类),java.lang.String就是object的子类。

  3. 子类方法的权限必须【大于等于】父类方法的权限修饰符。小扩展提示:public > protected > (default) > private备注:(default)不是关键字default,而是什么都不写,留空。

17.2 父子类构造方法

继承关系中,父子类构造方法的访问特点:

  1. 子类构造方法当中有一个默认隐含的“super()"调用,所以一定是先调用的父类构造,后执行的子类构造。
  2. 子类构造可以通过super关键字来调用父类重载构造。
  3. super的父类构造调用,必须是子类构造方法的第一个语句。不能一个子类构造调用多次super构造。

总结:子类必须调用父类构造方法,不写则赠送super();写了则用写的指定的super调用,super只能有一个.还必须是第一个。

17.3 super三种用法(访问父类)

  1. 在子类的成员方法中,访问父类的成员变量。
  2. 在子类的成员方法中,访问父类的成员方法。
  3. 在子类的构造方法中,访问父类的构造方法。public Zi(){super();}

17.4 this三种方法(访问本类)

  1. 在本类的成员方法中,访问本类的成员变量。
  2. 在本类的成员方法中,访问本类的另—个成员方法。
  3. 在本类的构造方法中,访问本类的另一个构造方法。

在第三种用法当中要注意:

A. this ( …)调用也必须是构造方法的第一个语句,唯一一个。

B.super和this两种构造调用,不能同时使用。

17.5 super和this内存图

18 抽象类

抽象方法:就是加上abstract关键字,然后去掉大括号,直接分号结束。

抽象类:抽象方法所在的类,必须是抽象类才行。在class之前写上abstract即可。

如何使用抽象类和抽象方法:

1.不能直接创建new抽象类对象。

2.必须用一个子类来继承抽象父类。

3.子类必须覆盖重写抽象父类当中所有的抽象方法。

覆盖重写(实现):子类去掉抽象方法的abstract关键字,然后补上方法体大括号。

4.创建子类对象进行使用。

19 微信发红包案例(⭐)

public class User {
    // 成员变量
    private String username; // 用户名
    private double leftMoney; // 余额
    // 构造方法
    public User() { 
    }
    
    public User(String username, double leftMoney) {
        this.username = username;
        this.leftMoney = leftMoney;
    }
    
    // get/set方法
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public double getLeftMoney() {
        return leftMoney;
    }
    public void setLeftMoney(double leftMoney) {
        this.leftMoney = leftMoney;
    }
    
    // 展示信息的方法
    public void show() {
        System.out.println("用户名:"+ username +" , 余额为:" + leftMoney + "元");
    }
}
public class QunZhu extends User {
    // 添加构造方法
    public QunZhu() {
    }
    public QunZhu(String username, double leftMoney) {
        // 通过super 调用父类构造方法
        super(username, leftMoney);
    }
    /*
    群主发红包,就是把一个整数的金额,分层若干等份。
    1.获取群主余额,是否够发红包.
    不能则返回null,并提示.
    能则继续.
    2.修改群主余额.
    3.拆分红包.
    3.1.如果能整除,那么就平均分。
    3.2.如果不能整除,那么就把余数分给最后一份。
    */
    public ArrayList<Double> send(int money, int count) {
        // 获取群主余额
      	double leftMoney = getLeftMoney();
        if(money > leftMoney) {
            return null;
        }
        // 修改群主余额的
        setLeftMoney(leftMoney ‐ money);
        // 创建一个集合,保存等份金额
        ArrayList<Double> list = new ArrayList<>();
        // 扩大100倍,相当于折算成'分'为单位,避免小数运算损失精度的问题
        money = money * 100;
        // 每份的金额
        int m = money / count;
        // 不能整除的余数
        int l = money % count;
        // 无论是否整除,n‐1份,都是每份的等额金额
        for (int i = 0; i < count ‐ 1; i++) {
            // 缩小100倍,折算成 '元'
            list.add(m / 100.0);
        }
        // 判断是否整除
        if (l == 0) {
            // 能整除, 最后一份金额,与之前每份金额一致
            list.add(m / 100.0);
        } else {
            // 不能整除, 最后一份的金额,是之前每份金额+余数金额
            list.add((m + l) / 100.00);
        }
        // 返回集合
        return list;
    }
}
public class Member extends User {
    public Member() {
    }
    public Member(String username, double leftMoney) {
        super(username, leftMoney);
    }
    // 打开红包,就是从集合中,随机取出一份,保存到自己的余额中
    public void openHongbao(ArrayList<Double> list) {
        // 创建Random对象
        Random r = new Random();
        // 随机生成一个角标
        int index = r.nextInt(list.size());
        // 移除一个金额
        Double money = list.remove(index);
        // 直接调用父类方法,设置到余额
        setLeftMoney( money );
    }
}

public class Test {
    public static void main(String[] args) {
        // 创建一个群主对象
        QunZhu qz = new QunZhu("群主" , 200);
        // 创建一个键盘录入
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入金额:");
        int money = sc.nextInt();
        System.out.println("请输入个数:");
        int count = sc.nextInt();
        // 发送红包
        ArrayList<Double> sendList = s.send(money,count);
        // 判断,如果余额不足
        if(sendList == null){
            System.out.println(" 余额不足...");
            return;
        }
        // 创建三个成员
        Member m = new Member();
        Member m2 = new Member();
        Member m3 = new Member();
        // 打开红包
        m.openHongbao(sendList);
        m2.openHongbao(sendList);
        m3.openHongbao(sendList);
        // 展示信息
        qz.show();
        m.show();
        m2.show();
        m3.show();
    }
}

20.1 抽象方法abstract

一定要覆盖重写,否则报错。

通过实现类的对象来调用。

不用写方法体。

20.2 默认方法default

假设有一个很大很大的项目,一个接口被很多很多的类所实现,大家都平安无事平稳地运行着。突然有一天,出现了一个小小地问题,或者说有一个更好的优化方案,需要在这些实现类去增加。在默认方法出现之前,只有抽象方法,且需要在实现类中给出具体定义才能操作,那岂不是只能两眼一闭,直接从早干到晚地添加啦。
但是,默认方法地出现允许在接口中给出方法的具体实现,且实现类中能够自动实现默认方法,我只需要将这个优化放在接口的默认方法里面,就能完成对所有实现类的优化啦。

可覆盖重写也可以不, 二选一。

但是只能通过实现类的对象来调用。

要写方法体。

20.3 静态方法static

在没有新增静态方法之前,我们如果想让一些固定的操作在接口中出现,就必须定义一个和接口配套的实现类。而接口中静态方法的出现,可以直接通过接口调用静态方法。

就很直接地在接口中定义静态方法,且可以被接口直接调用,不需要再定义与其配套的实现类,多舒服哦。

不能在实现类里重写静态方法。

不能通过接口实现类的对象来调用接口当中的静态方法。 一定要通过接口名称直接调用其中的静态方法。

要写方法体。

20.4 私有方法private

问题背景:我们需要抽取一个公共方法,用来解决默认方法之间重复代码的问题。但这个共有方法不应该让实现类使用,应该是私有化的

1.普通私有方法,解决多个默认方法之间重复代码问题格式:

private 返回值类型 方法名称(参数列表){
    方法体
}

2.静态私有方法,解决多个静态方法之间重复代码问题格式:

private static 返回值类型 方法名称(参数列表){
	方法体
}

20.5 接口常量

接口当中也可以定义“成员变量”,但是必须使用public static final三个关键字进行修饰。

从效果上看,这其实就是接口的【常量】。

public static final 数据类型常量名称 = 数据值 ;

—旦使用final关键字进行修饰,说明不可改变。

注意事项:
1.接口当中的常量,可以省略public static final,注意:不写也照样是这样。

2.接口当中的常量,必须进行赋值;不能不赋值。

3.接口中常量的名称,使用完全大写的字母,用下划线进行分隔。(推荐命名规则)

20.6 接口注意事项

1.接口是没有静态代码块或者构造方法的。

2.一个类的直接父类是唯一的,但是一个类可以同时实现多个接口。

public class MyInterfaceImpl implements MyInterfaceA,MyInterfaceB {/覆盖重写所有抽象方法
}

3.如果实现类所实现的多个接口当中,存在重复的抽象方法,那么只需要覆盖重写一次即可。

4.如果实现类没有覆盖重写所有接口当中的所有抽象方法,那么实现类就必须是一个抽象类。

5.如果实现类锁实现的多个接口当中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖重写。

6.一个类如果直接父类当中的方法,和接口当中的默认方法产生了冲突,优先用父类当中的方法。

20.7 接口多继承

1.类与类之间是单继承的。直接父类只有一个。

2.类与接口之间是多实现的。一个类可以实现多个接口。

3.接口与接口之间是多继承的。

注意事项:

1、多个父接口当中的抽象方法如果重复,没关系。
2、多个父接口当中的默认方法如果重复,那么子接口必须进行默认方法的覆盖重写【而且带着default关键字】

子接口重写默认方法时,default关键字可以保留。

子类重写默认方法时,default关键字不可以保留。

21 多态性

21.1 成员方法

因为方法覆盖重写,所以调用的是重写后的Zi的method(),此时方法看等号右边。

编译看左边,运行看右边。

Fu obj = new Zi();
obj.method();
//子

21.2 成员变量

不会覆盖重写,所以要看等号左边是谁,优先用谁,没有则向上找。

编译看左边,运行还看左边。

Fu obj = new Zi();
sout(obj.num);
//父

多态性的优势:https://www.cnblogs.com/lv-suma/p/12842575.html

由于多态特性的支持,showAnimalEat方法的Animal类型,是Cat和Dog的父类类型,父类类型接收子类对象,当 然可以把Cat对象和Dog对象,传递给方法。

当eat方法执行时,多态规定,执行的是子类重写的方法,那么效果自然与showCatEat、showDogEat方法一致, 所以showAnimalEat完全可以替代以上两方法。

不仅仅是替代,在扩展性方面,无论之后再多的子类出现,我们都不需要编写showXxxEat方法了,直接使用 showAnimalEat都可以完成。

所以,多态的好处,体现在,可以使程序编写的更简单,并有良好的扩展。

21.3 对象向上转型

21.4 对象向下转型

向上转型一定是安全的,没有问题的,正确的。但是也有一个弊端:对象一旦向上转型为父类,那么就无法调用子类原本特有的内容。

解决方案:用对象的向下转型还原。

21.5 instanceof

变量名 instanceof 数据类型

如果变量属于该数据类型,返回true。

如果变量不属于该数据类型,返回false。

22 笔记本电脑案例(⭐)

笔记本电脑(laptop)通常具备使用USB设备的功能。在生产时,笔记本都预留了可以插入USB设备的USB接口,但具体是什么USB设备,笔记本厂商并不关心,只要符合USB规格的设备都可以。

定义USB接口,具备最基本的开启功能和关闭功能。鼠标和键盘要想能在电脑上使用,那么鼠标和键盘也必须遵守 USB规范,实现USB接口,否则鼠标和键盘的生产出来也无法使用。

package cn.itcast.day08.demo06;

public interface USB {
    void open();
    void close();
}
package cn.itcast.day08.demo06;

public class KeyBoard implements USB {
    @Override
    public void open() {
        System.out.println("键盘开启,绿灯闪一闪。");
    }

    @Override
    public void close() {
        System.out.println("键盘关闭,绿灯熄灭.");
    }

    public void click(){
        System.out.println("键盘敲击。");
    }
}
package cn.itcast.day08.demo06;

public class Mouse implements USB {
    @Override
    public void open() {
        System.out.println("鼠标开启,红灯闪一闪。");
    }

    @Override
    public void close() {
        System.out.println("鼠标关闭,红灯熄灭。");
    }
    public void click(){
        System.out.println("鼠标单击。");
    }
}
package cn.itcast.day08.demo06;

public class Lap{
    public void powerOn(){
        System.out.println("开机!");
    }
    public void powerOff(){
        System.out.println("关机!");
    }

    public void useDevice(USB usb){
        //这里不能直接调用usb.click,必须向下转型
        if(usb!= null){
            usb.open();
            if(usb instanceof Mouse){
                Mouse m = (Mouse) usb;
                m.click();
            }else if(usb instanceof KeyBoard){
                KeyBoard k = (KeyBoard) usb;
                k.click();
            }
            usb.close();
        }
    }
}
package cn.itcast.day08.demo06;

public class Demo01 {
    public static void main(String[] args) {
        Lap lt = new Lap();
        lt.powerOn();
        USB u = new Mouse();
        lt.useDevice(u);

        KeyBoard kb = new KeyBoard();
        lt.useDevice(kb);//自动发生向上转型

        lt.powerOff();
    }
}

23 final

23.1 类

public final class 类名 {
}

查询API发现像 public final class String 、 public final class Math 、 public final class Scanner 等,很多我们学习过的类,都是被final修饰的,目的就是供我们使用,而不让我们所以改变其内容。

23.2 方法

修饰符 final 返回值类型 方法名(参数列表){
    //方法体
}

重写被 final 修饰的方法,编译时就会报错。

23.3 局部变量

21.3.1 基本类型

被final修饰后,只能赋值一次,不能再更改

变量当中的数据不可改变

21.3.2 引用类型

引用类型的局部变量,被final修饰后,只能指向一个对象 ,地址值不可改变,但是不影响对象内部的成员变量值的修改 。

23.4 成员变量

成员变量具有默认值所以用了final之后必须手动赋值,不会再给默认值。

对于final的成员变量,要么使用直接赋值,要么通过构造方法赋值。

必须保证类当中所有重载的构造方法,都最终会对final的成员变量进行赋值。

被final修饰的常量名称,一般都有书写规范,所有字母都大写。

24 四种权限修饰符

public:公共的

protected:受保护的

default:默认的

private:私有的

编写代码时,如果没有特殊的考虑,建议这样使用权限:

  1. 成员变量使用 private ,隐藏细节。
  2. 构造方法使用 public ,方便创建对象。
  3. 成员方法使用 public ,方便调用方法。

小贴士:不加权限修饰符,其访问能力与default修饰符相同

25 内部类

将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类。

访问特点:

  1. 内部类可以直接访问外部类的成员,包括私有成员。
  2. 外部类要访问内部类的成员,必须要建立内部类的对象。

访问方式:

  1. 间接方式:在外部类方法中,使用内部类,然后main只调用外部类的方法。
  2. 直接方式: 外部类名.内部类名 对象名 = new 外部类型().new 内部类型();

内部类仍然是一个独立的类,在编译之后会内部类会被编译成独立的.class文件,但是前面冠以外部类的类名 和$符号 。

比如,Person$Heart.class

25.1 重名

外部类成员变量内部类成员变量内部类局部变量重名

25.2 局部内部类

25.2.1 定义

如果一个类是定义在一个方法内部的,那么这就是一个局部内部类。
“局部”:只有当前所属的方法才能使用它,出了这个方法外面就不能用了。

25.2.2 定义格式

只要之后在psvm中调用Outer.methodOuter()方法就行

25.2.3 局部内部类里的final

25.2.4 注意事项

25.3 匿名内部类

25.3.1 定义

是内部类的简化写法。它的本质是一 带具体实现的 父类或者父接口的 匿名的 子类对象。

25.3.2 定义格式

接口名称 对象名 = new 接口名称(){

​ //覆盖重写所有抽象方法

对格式"new 接口名称(){…}"进行解析:

1、new代表创建对象的动作

2、接口名称才是匿名内部类需要实现哪个接口

3、{……}这才是你们内部类的内容

25.3.3 注意

1.匿名内部类,在【创建对象】的时候,只能使用唯一一次。
如果希望多次创建对象,而且类的内容一样的话,那么就必须使用单独定义的实现类了。

2.匿名对象,在【调用方法】的时候,只能调用唯——次。
如果希望同一个对象,调用多次方法,那么必须给对象起个名字。

3.匿名内部类是省略了【实现类/子类名称】,但是匿名对象是省略了【对象名称】

26 引用类型用法总结

基本类型可以作为成员变量、作为方法的参数、作为方法的返回值,那么当然引用类 型也是可以的。

26.1 class作为成员变量

类作为成员变量时,对它进行赋值的操作,实际上,是赋给它该类的一个对象。

class Weapon {
    String name; // 武器名称
    int hurt; // 伤害值
}
class Role {
    int id;
    int blood;
    String name;
    // 添加武器属性
    Weapon wp;

    // 提供get/set方法
    public Weapon getWp() {
       return wp;
    }
    public void setWeapon(Weapon wp) {
        this.wp = wp;
    }

    // 攻击方法
    public void attack(){
        System.out.println("使用"+ wp.getName() +", 造成"+wp.getHurt()+"点伤害");
    }
}
public class Test {
    public static void main(String[] args) {
        // 创建Weapon 对象
        Weapon wp = new Weapon("屠龙刀" , 999999);
        // 创建Role 对象
        Role r = new Role();
        // 设置武器属性
        r.setWeapon(wp);
        // 攻击
        r.attack();
    }
}
输出结果:
使用屠龙刀,造成999999点伤害

26.2 interface作为成员变量

接口是对方法的封装,对应游戏当中,可以看作是扩展游戏角色的技能。所以,如果想扩展更强大技能,我们在 Role 中,可以增加接口作为成员变量,来设置不同的技能。

// 法术攻击
public interface FaShuSkill {
	public abstract void faShuAttack();
}
public class Role {
    FaShuSkill fs;
    public void setFaShuSkill(FaShuSkill fs) {
        this.fs = fs;
    }
    // 法术攻击
    public void faShuSkillAttack(){
        System.out.print("发动法术攻击:");
        fs.faShuAttack();
        System.out.println("攻击完毕");
    }
}
public class Test {
    public static void main(String[] args) {
        // 创建游戏角色
        Role role = new Role();
        // 设置角色法术技能
        role.setFaShuSkill(new FaShuSkill() {
            @Override
            public void faShuAttack() {
                System.out.println("纵横天下");
            }
        });
        // 发动法术攻击
        role.faShuSkillAttack();
        // 更换技能
        role.setFaShuSkill(new FaShuSkill() {
            @Override
            public void faShuAttack() {
                System.out.println("逆转乾坤");
            }
        });
        // 发动法术攻击
        role.faShuSkillAttack();
    }
}
输出结果:
发动法术攻击:纵横天下
攻击完毕
发动法术攻击:逆转乾坤
攻击完毕

我们使用一个接口,作为成员变量,以便随时更换技能,这样的设计更为灵活,增强了程序的扩展性。 接口作为成员变量时,对它进行赋值的操作,实际上,是赋给它该接口的一个子类对象。

26.3 interface作为方法参数和返回值类型

当接口作为方法的参数时,需要传递什么呢?当接口作为方法的返回值类型时,需要返回什么呢?对,其实都是它的 子类对象。 ArrayList 类我们并不陌生,查看API我们发现,实际上,它是 java.util.List 接口的实现类。所 以,当我们看见 List 接口作为参数或者返回值类型时,当然可以将 ArrayList 的对象进行传递或返回。

27 拼手气红包案例(⭐)

public interface OpenMode {
/**
* @param totalMoney 总金额,单位是"分"。总金额为方便计算,已经转换为整数,单位为分。
* @param count 红包个数
* @return ArrayList<Integer> 元素为各个红包的金额值,所有元素的值累和等于总金额.
*
* 请将totalMoney,分成count分,保存到ArrayList<Integer>中,返回即可.
*/
public abstract ArrayList<Integer> divide(int totalMoney, int count);
}
public class RedPacketTest {
    public static void main(String[] args) {
        // 创建红包对象
        RedPacket rp = new RedPacket("大红包");
        // 设置群主名称
        rp.setOwnerName("我是群大大");
        // 设置红包类型
        rp.setOpenMode(new Common()); // 普通红包
    }
}

public class Common implements OpenMode {
    @Override
    public ArrayList<Integer> divide(int totalMoney, int count) {
        // 创建保存各个红包金额的集合
        ArrayList<Integer> list = new ArrayList<>();
        // 定义循环次数,总个数‐1次
        int time = count ‐ 1;
        // 一次计算,生成平均金额
        int money = totalMoney / count;
        // 循环分配
        for (int i = 0; i < time; i++) {
            // 添加到集合中
            list.add(money);
            // 总金额扣除已分配金额
            totalMoney ‐= money;
        }
        // 剩余的金额,为最后一个红包
        list.add(totalMoney);
        System.out.println("普通红包金额:" + list);
        // 返回集合
        return list;
    }
}
public class RedPacketTest {
    public static void main(String[] args) {
        // 创建红包对象
        RedPacket rp = new RedPacket("大红包");
        // 设置群主名称
        rp.setOwnerName("我是群大大");
        // 设置红包类型,二选一
        // rp.setOpenMode(new Common()); // 普通红包
        rp.setOpenMode(new Lucky()); // 手气红包

    }
}
public class Lucky implements OpenMode {
    @Override
    public ArrayList<Integer> divide(int totalMoney, int count) {
        // 创建保存各个红包金额的集合
        ArrayList<Integer> list = new ArrayList<>();
        // 定义循环次数,总个数‐1次
        int time = count ‐ 1;
        // 创建随机数对象
        Random random = new Random();
        // 循环分配
        for (int i = 0; i < time; i++) {
            /*
            * 每次重新计算,生成随机金额
            * 随机范围: totalMoney / count * 2,totalMoney不断的减少,
            * count也不断的减少,所以这是一个可变化的范围.
            */
            int money = random.nextInt(totalMoney / count * 2) + 1;
            // 金额添加到集合
            list.add(money);
            // 总金额扣除已分配金额
            totalMoney ‐= money;
            // 红包个数‐1
            count‐‐;
        }
        // 剩余的金额,为最后一个红包
        list.add(totalMoney);
        return list;
    }
}

基础篇结束啦!

下一篇进阶知识01请查阅:
https://blog.csdn.net/weixin_45860674/article/details/119650957


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK