Java 基础知识学习2

IDEA使用学习


IDEA快捷键

一、方法

方法其实就是若干语句的功能集合

方法好比一个工厂
蒙牛工厂 原料:奶牛、饲料、牛
  产出物:奶制品
钢铁工厂 原料:铁矿石、煤炭
  产出物:钢铁建材

参数:(原料):就是进入方法的数据
返回值:(产出物):就是从方法中出来的数据。

定义方法的完整格式:

修饰符 返回值类型 方法名称(参数类型 参数名称,...){
  方法体
  return 返回值;

修饰符:现阶段的固定写法 public static
返回值类型:也就是方法最终产生的数据结果是什么类型
方法名称:方法的名称,规则和变量一样,小驼峰
参数类型:进入方法的数据是什么类型
参数名称:进入方法的数据对应的变量名称
ps:参数如果有多个使用,分隔
方法体:方法需要做的事情,若干行代码
return:两个作用,第一停止当前方法,第二将后面的返回值还给调用处
返回值:也就是方法执行后最终产生的数据结果
注意:return后面的返回值,必须和方法名称前面的返回值类型保持对应

定义一个另个int数字相加的方法 三要素:

返回值类型:int
方法名称:sum
参数列表:int a, int b

方法的三种调用格式:

1.单独调用:方法名称(参数)
2.打印调用:System.out.println(方法名称(参数));
3.赋值调用;数据类型 变量名称 = 方法名称(参数);
注意:此前学习的方法:返回值类型固定写为void,这种方法只能够单独使用,不能进行打印调用和赋值调用

赋值调用的四个步骤

对比有参数和无参数的区别

有参数:小括号当中有内容,当一个方法需要一些数据条件,才能完成任务的时候就是有参数

例如两个数字相加,必须知道两个数字是格子多少才能相加

无参数:小括号当中留空。一个方法不需要任何数据条件,自己就能独立完成任务,就是无参数。

例如定义一个方法,打印固定10次Helloworld。

public class Demo03MethodParam {
    public static void main(String[] args) {
        method1(10, 20);
        method2();
    }
    public static void method1(int a, int b){
        int result = a * b;
        System.out.println("结果是:" + result);
    }
    public static void method2(){
        for (int i = 0; i < 10; i++) {
            System.out.println("HelloWorld" + i);
        }
    }
}
有无参数对比
有无返回值对比

注意事项:
对于有返回值的方法,可以使用单独调用、打印调用或者赋值调用
但是对于无返回值的方法,只能使用单独调用,不能使用打印调用或者赋值调用

public class Demo04MethodReturn {
    public static void main(String[] args) {
        int num = getSum(10,20);
        System.out.println(num);
        getNum(20,30);
    }
    public static int getSum (int a, int b){
        int result = a + b;
        return result;
    }
    public static void getNum(int a, int b){
        int result = a + b;
        System.out.println(result);
    }
}

使用方法的时候,注意事项:

1. 方法应该定义在类当中,但是不能再方法当中再定义方法,不能嵌套
2. 方法定义的前后顺序无所谓
3. 方法定义之后不会执行,如果希望执行,一定要调用,单独调用 打印调用 赋值调用
4. 如果方法有返回值,那么必须写上“return 返回值”,不能没有
5. return后面的返回值数据,必须和方法的返回值类型对应
6. 对于一个void没有返回值的方法,不能写return后面的返回值,只能写return自己
7. 对于void方法当中最后一行的return可省略不写,功能只是结束方法的执行而已。
8. 一个方法当中可以有多个return语句,但是必须保证同时只有一个会被执行到,两个return不能连写。

public static int getMax(int a, int b){
        if(a > b){
            return a;
        }else {
            return b;
        }
    }

方法的重载

对于功能类似的方法来说,因为参数列表不一样,却需要记住那么多不同的方法名称,非常麻烦

方法的重载(overload):多个方法的名称一样,但是参数不一样。
优点:只需要记住唯一一个方法名称,就可以实现类似的多个功能。

1. 参数个数不同
2. 参数类型不同
3. 参数多类型的顺序不同

方法的重载:

1. 参数的名称无关
2. 与方法的返回值类型无关

二、数组

数组创建的初始化方式:

1. 动态初始化(指定长度):在创建数组的时候,直接指定数组的数据元素个数。
2. 静态初始化(指定内容):在创建数组的时候,不直接指定数据个数多少,而是直接将具体的数据内容进行指定。

静态初始化基本格式:(两种格式)
数据类型 [] 数组名称 = new 数据类型[] {元素1,元素2,...}
数据类型 [] 数组名称 = {元素1,元素2,...}
注意事项:
1.静态初始化没有直接告诉长度,但是根据元素内容可以自动推算出长度。
2.静态初始化标准格式可以拆分为两个步骤。
3.动态初始化也可以拆分成为两个步骤。
4.静态初始化一旦使用省略格式,就不能拆分为两个步骤。

public class Demo01Array {
    public static void main(String[] args) {
        // 标准格式初始化
        int[] arrayA = new int[]{5, 2, 15};
        
        // 省略格式初始化
        String[] arrayB ={"Hello","World"};
        
        // 静态初始化拆分两个格式初始化
        int[] arrayC;
        arrayC = new int[] {11,12,13};
        
        // 动态初始化拆分两个格式初始化
        int[] arrayE;
        arrayE = new int[5];
        
        // 静态初始化的省略格式,不能拆分为两个步骤
//        int[] arrayD;
//        arrayD = {1,2,3};   // 报错
    }
}

动态初始化数组的格式:

数据类型[ ] 数组名称 = new 数组类型 [数组长度];

解析含义:

左侧数据类型:也就是数组当中保存的数据,全都是统一的什么类型
左侧的中括号:代表我是一个数组
左侧数组名称:给数组去一个名字
右侧的new:代表穿件数组的动作
右侧数据类型:必须和左边的数据类型保持一致
右侧中括号的长度:也就是数组当中,当地可以保存多少个数据,是一个int数字

使用建议
如果不确定数组当中的具体内容,用动态初始化;否则,已经确定了具体的内容,用静态初始化。

直接打印数组名称,得到的式数组对应的内存地址哈希值
二进制:01
十进制:0123456789
十六进制:0123456789abcdef、

访问数据元素的格式:数组名称[索引值]
索引值:就是一个int数字,代表数组当中元素的编号
【注意】索引值从0开始,一直到“数组长度-1”为止

public class Demo02ArrayUse {
    public static void main(String[] args) {
        // 静态初始化的省略格式
        int[] array = {10,2,3};
//        System.out.println(array); // [I@119d7047 内存地址哈希值
        
        // 直接打印数组的元素
        System.out.println(array[0]);
        System.out.println(array[1]);
        System.out.println(array[2]);
        
        // 将数组中的元素赋值给变量
        int num = array[2];
        System.out.println(num);

    }
}

动态初始化数组:元素自动拥有一个默认值。规则如下:
整数类型:默认为0
浮点类型:默认为0.0
字符类型:默认为‘\u0000’
布尔类型:默认fales
引用类型:默认为null
注意事项:
静态初始化也有默认值的过程,只不过系统自动将默认值替换成元素的内容

Java内存划分
数组内存

数组索引越界异常:ArrayIndexOutOfBoundsException,为超出数组索引,更正即可
空指针异常:NullPointerException,没有进行new创建,补上即可
数组长度格式:数组名称.length
new创建的才是数组

名称是一个却是两个数组

遍历数组:
循环+数组. length

public class Demo04ArrayReverse {
    public static void main(String[] args) {
        int array[] = {1,2,3,4,5};
        printArray(array);
        System.out.println("==========");
        for (int min = 0, max = array.length-1; min < max; min++, max--) {
            int temp = array[min];
            array[min] = array[max];
            array[max] = temp;
        }
        printArray(array);

    }
    public static void printArray(int[] array){
        for (int i = 0; i < array.length; i++) {
            System.out.println(array[i]);
        }
    }
}

数组反转

数组作为方法的返回值
数组作为方法的参数,传递进去的其实是数组的地址值
数组作为方法的返回值,返回的也是数字的地址值

public class Demo05ArrayReturn {
    public static void main(String[] args) {
        int[] result = caculate(10,20,30);
        System.out.println("main方法接收的数组返回值" + result);
        System.out.println("总和" + result[0]);
        System.out.println("平均值" + result[1]);
    }
    public static int[] caculate(int a, int b, int c){
        int sum = a + b + c;
        int avg = sum / 3;
        int[] array = {sum, avg};
        System.out.println("caculate的地址值" + array);
        return array;
    }
}

数组返回值

三、面向对象

面向过程:强调步骤
面向对象:强调对象 (三大特征:封装、继承和多态)

package cn.itcast.day0404.demo01;

import java.util.Arrays;

public class Demo01PrintArray {
    public static void main(String[] args) {
        // 面向过程:当需要实现一个功能的时候,每一个具体的步骤都要亲力亲为,详细处理每一个细节
        int[] array = {10, 20, 30, 40};
        System.out.print("[");
        for (int i = 0; i < array.length; i++) {
            if(i == array.length-1){
                System.out.println(array[i] + "]");
            }else {
                System.out.print(array[i] + ", ");
            }
        }
        System.out.println("=================");
        // 面向对象: 当需要实现一个功能的时候,不关心具体的步骤,而是找一个已经具备该功能的人,来帮我做事。
        // 找一个JDK给我们提供的Array类
        // 其中有一个toString方法,直接就能把数组变成想要的格式的字符串
        System.out.println(Arrays.toString(array));
    }
}
面向过程与面向对象

成员变量

注意事项:
1. 成员变量是直接定义在类当中的,在方法外边
2. 成员方法不要写static关键字

通常情况下,一个类并不能直接使用,需要根据类创建一个对象,才能使用
1.导包:也就是支出需要使用的类,在什么位置
import 包名称.类名称
import cn.itcast.day0404.demo01.Student;
2.创建,格式:
类名称 对象名 = new 类名称();
Student stu = new Student();
3.使用,分为两种情况
使用成员变量:对象名.成员变量名
使用成员方法:对象名.成员方法名(参数)
(也就是,想用水就用对象名点谁)

package cn.itcast.day0404.demo01;
/*
注意事项:
1. 成员变量是直接定义在类当中的,在方法外边
2. 成员方法不要写static关键字
* */
public class Student {
    // 成员变量
    String name; // 姓名
    int age;
    // 成员方法
    public  void eat(){
        System.out.println("吃饭饭");
    }
    public void sleep(){
        System.out.println("睡觉");
    }
    public void study(){
        System.out.println("学习");
    }

}
    public static void main(String[] args) {
        Student stu = new Student();
        System.out.println(stu.name);
        System.out.println(stu.age);
        System.out.println("==================");
        // 改变对象当中的成员变量数值内容
        // 将右侧的字符串,赋值交给stu对象当中的name成员变量
        stu.name = "赵丽颖";
        stu.age = 18;
        System.out.println(stu.name);
        System.out.println(stu.age);
        // 使用对象的成员方法:对象名.成员方法名();
        stu.eat();
    }
}

调用成员变量

入栈 = 压栈
调用方法后会立刻出栈
一个对象的内存图

两个对象的内存图
两个对象产生联系的内存图

当一个对象作为参数,传递到方法当中时,实际上传递进去是对象的地址值

对象作为方法的参数
返回值为自定义类

局部变量和成员变量

1. 定义的位置不一样【重点】
局部变量:在方法的内容
成员变量:在方法的外部,直接写在类当中
2. 作用范围不一样【重点】
局部变量:只有方法当中才可以使用,出了方法就不能再用
成员变量:整个类全都可以通用
3. 默认值不一样【重点】
局部变量:没有默认值,如果要使用,必须手动进行赋值
成员变量:如果没有赋值,会有默认值,规则和数组一样
4. 内存的位置不一样(了解)
局部变量:位于栈内存
成员变量:位于堆内存
5. 生命周期不一样(了解)
局部变量:随着方法进栈而诞生,随着方法出栈而消失
成员变量:随着对象创建而诞生,随着对象被垃圾回收而消失

private关键字
public class Person {
    String name;
    private int age;

    public void show(){
        System.out.println("我叫:" + name + "年龄:" + age);
    }
    // 这个成员方法,专门用于向age设置数据
    public void setAge(int num){
        if(num < 100 && num >= 9){
            age = num;
        } else {
            System.out.println("数据不合理");
        }


    }
    // 这个成员方法:专门私密获取age的数据
    public int getAge(){
        return age;
    }
}
public class Demo03Person {
    public static void main(String[] args) {
        Person person = new Person();
        person.show();

        person.name = "赵丽颖";
        person.setAge(-20);
        person.show();
    }
}
private关键字

问题描述:定义Person的年龄时,无法阻止不合理的数值被设置进来。
解决方案:用private关键字将需要保护的成员变量进行修饰

一旦使用了private进行修饰,那么本类当中仍然可以随意访问
但是!超出本类范围之外就不能再直接访问

直接访问private成员变量,就定义一对Getter/Setter方法
必须叫setXxx或者getXxx命名规则
对于Getter来说,不能有参数,返回值类型和成员变量对应。
对于Setter来说,不能有返回值,参数类型和成员变量对应。

优点:
提高代码的安全性,阻止不合理的情况出现。

this关键字

当方法的局部变量和类的成员变量重名的时候,根据“就近原则”,优先使用局部变量
如果需要访问本类当中的成员变量,需要使用格式
this.成员变量名
“通过调用的方法,就是this”

public class Person {
    String name;
    public void sayHello(String name){
        System.out.println(name + ",你好,我是" + this.name);
        System.out.println(this);
    }
}
public class Demo01Person {
    public static void main(String[] args) {
        Person person = new Person();
        person.name = "王思聪";
        person.sayHello("王健林");
        System.out.println(person);
    }
}

this是谁?
构造方法

是专门用来创建对象的方法,当我们通过关键字new来创建对象时,其实就是在调用构造方法。
格式
public 类名称(参数类型 参数名称){
方法体
}
注意事项:
1. 构造方法的名称必须和所在的类名称完全一致,区分大小写
2. 构造方法不要写返回值类型,连void都不写
3. 构造方法不能return一个具体返回值
4. 如果没有编写任何构造方法,那么编译器将自动默认赠送一个构造方法,没有参数方法体什么事情都不做。
5. 一旦编写了至少一个构造方法,那么编译器不再赠送
6. 构造方法也是可以进行重载的
重载:方法名称相同,参数列表不同

public class Student {
    private String name;
    private int age;
    public Student(){
        System.out.println("无参构造方法执行啦!");
    }
    public Student(String name, int age){
        System.out.println("有参构造方法执行啦");
        this.name = name;
        this.age = age;
    }
    public void setName(String name){
        this.name = name;
    }
    public String getName(){
        return name;
    }
    public void getAge(int age){
        this.age = age;
    }
    public int getAge(){
        return age;
    }

}
public class Demo02Student {
    public static void main(String[] args) {
        Student stu = new Student();

        Student stu2 = new Student("李四",20);
        System.out.println("名字:" + stu2.getName() + " 年龄:" + stu2.getAge());
        stu2.setName("张三");
        System.out.println("名字:" + stu2.getName() + " 年龄:" + stu2.getAge());
    }
}
setter可以修改name的内容

四、API

Scanner 类的功能:可以实现键盘输入数据到程序当中
引用类型用的一般使用步骤
1. 导包
import 包路径.类名称
如果需要使用的目标类、和当前类位于同一个包下,则可以省略导包语句不写。
只有java.long包下内容不需要导包,其他的包都需要import语句。

2. 创建
类名称 对象名 = new 类名称();

3. 使用
对象名.成员方法名();

获取键盘输入的一个int数字,sc.nextInt();
获取键盘输入的一个String数字,sc.next();

import java.util.Scanner;
public class Demo01Scanner {
    public static void main(String[] args) {
        // System.in 表示从键盘输入
        Scanner sc = new Scanner(System.in);
        String str = sc.next();
        int num = sc.nextInt();
        System.out.println("字符:" + str);
        System.out.println("数字:" + num);
    }
}
Scanner

例题:

键盘输入两个数字并求和~

import java.util.Scanner;

public class Demo01ScannerSum {
    public static void main(String[] args) {
        // System.in 键盘的输入语句
        Scanner sc = new Scanner(System.in);
        int num1 = sc.nextInt(), num2 = sc.nextInt();
        System.out.println("两者的和为:" + (num1 + num2) ) ;

    }
}

打印输出
匿名对象:
import java.util.Scanner;

public class Demo01Anonymous {
    public static void main(String[] args) {
       
        // 一般方法进行调用
        Scanner sc = new Scanner(System.in);
        new Person().name = sc.next();
        new Person().showName();
        
        methParam(sc);
        // 匿名对象进行传参
        methParam(new Scanner(System.in));

        //用匿名对象作返回值
        System.out.println(methodReturn().nextInt());
    }

    public static void methParam(Scanner sc) {
        
        int i = sc.nextInt();
        System.out.println(i);
    }
    public static Scanner methodReturn(){
        return new Scanner(System.in);
    }
}
匿名对象的调用
Random

Random类用来生成随机数字。使用三步骤:
1. 导包
import java.util.Random;
2. 创建
Random r = new Random();
3. 使用
获取一个随机的int数字(范围是int所有范围,有正负两种):int num = r.nextInt();
获取一个随机的int数字(参数代表了范围,左闭右开区间):int num = r.nextInt(3);
实际上代表的含义是:[0,3),也就是0-2
例题:
猜数字小游戏,并在指定的次数内猜对


import java.util.Random;
import java.util.Scanner;

public class Demo01Random {
    public static void main(String[] args) {
        Random r = new Random();
        int i = r.nextInt(100);
        Scanner sc = new Scanner(System.in);
        for (int j = 0; j < 5; j++) {
            int a = sc.nextInt();
            if (i < a){
                System.out.println("猜大了");
            } else if (i > a){
                System.out.println("猜小了");
            } else {
                System.out.println("猜对了");
                break;
            }
            if (j == 5 && i != a){
                System.out.println("游戏结束,你输了");
            }
        }
    }
}

次数内猜对

次数内未猜对
ArrayList

数组的长度不可以发生改变
ArrayList集合的长度是可以随意变化的
ArrayList:E代表泛型
泛型:装在集合当中的所有元素,全都是统一的类型
注意:泛型只能是引用类型,不能是基本类型
注意事项:
对于ArrayList 集合来说,直接打印得到的不是地址值,而是内容
如果内容是空,则输出[ ],

import java.util.ArrayList;

public class Demo01ArrayList {
    public static void main(String[] args) {
        ArrayList list = new ArrayList<>();
        System.out.println(list);
    }
}
打印结果
import java.util.ArrayList;

public class Demo01ArrayList {
    public static void main(String[] args) {
        ArrayList list = new ArrayList<>();
        System.out.println(list);  //  []
        // 向集合中添加数据
        list.add("赵丽颖");
        System.out.println(list);
        list.add("古力娜扎");
        list.add("迪丽热巴");
        System.out.println(list);
    }
}
ArrayList.add
ArrayList当中的常用方法有:

public boolean add(E e): 向集合当中添加元素,参数的类型和泛型一致

注意:对于ArrayList集合来说,add添加动作一定式成功的,所以返回值可用可不用
对于其他的集合,add添加动作不一定成功

public E get (int index):从集合中获取元素,参数式索引编号,返回值就是对应为止的元素
public E remove(int index):从集合中删除元素,参数式索引编号,返回值就是被删除掉的元素
public int size():获取集合的尺寸长度,返回值式集合中包含的元素个数。

import java.util.ArrayList;

public class Demo02ArrayListMethod {
    public static void main(String[] args) {
        ArrayList list = new ArrayList<>();
        System.out.println(list);

        boolean success = list.add("李白");// ArrayList 添加的返回值
        System.out.println(list);
        System.out.println("添加的动作是否成功:" + success);

        list.add("张三");
        list.add("李四");
        list.add("吴磊");
        System.out.println(list);

        // 从集合中获取元素:get 索引值从0开始
        String name = list.get(2);
        System.out.println("第二号索引位置:" + name);

        String whoRemove = list.remove(3);
        System.out.println("被删掉的人是谁" + whoRemove);
        System.out.println(list);
        int size = list.size();
        System.out.println("集合的长度为:" + size);

    }
}

集合的常用方法
集合的遍历
import java.util.ArrayList;

public class Demo03ArrayListEach {
    public static void main(String[] args) {
        ArrayList list = new ArrayList<>();
        list.add("李白");
        list.add("张三");
        list.add("李四");
        list.add("苏轼");
        for (int i = 0; i < list.size(); i++) {
            System.out.println("第" + (i+1) + "个元素是:" + list.get(i));
        }
    }
}

ArrayList遍历

ArrayList 存储基本类型数据,使用包装类
基本类型 包装类
byte    Byte
short    Short
int     Integer 【特殊】
long    Long
float    Float
double   Double
char    Character 【特殊】
boolean   Boolean
自动装箱:基本类型 ---> 包装类型(引用类型)
自动拆箱:包装类型 ---> 基本类型

例题1:
  随机生成6个数字并添加至集合中,并遍历该集合

import java.util.ArrayList;
import java.util.Random;

public class Demo06ArrayListEachBasic {
    public static void main(String[] args) {
        ArrayList list = new ArrayList<>();
        Random random = new Random();
        for (int i = 0; i < 6; i++) {
            list.add(random.nextInt(33)+1);
        }
        System.out.println(list);
        for (int i = 0; i < list.size(); i++) {
            System.out.println("第" + (i+1) + "个元素:" + list.get(i));
        }
    }
}

例题1

例题2:
自定义4个学生对象,添加到集合并遍历


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

    public Student() {
    }

    public Student(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;
    }
}

import java.util.ArrayList;

public record Demo08Person() {
    public static void main(String[] args) {
        ArrayList list = new ArrayList<>();
        Student one = new Student("李白",10);
        Student two = new Student("张三",20);
        Student four = new Student("李四",30);
        Student three = new Student("苏轼",40);
        list.add(one);
        list.add(two);
        list.add(four);
        list.add(three);
        for (int i = 0; i < list.size(); i++) {
            System.out.println("第" + (i + 1) + "个元素:名字为:" + list.get(i).getName() + ";年龄为:" + list.get(i).getAge());
        }
    }

}

例题2

例题3
定义一个方法,该方法可以打印出,将[]替换成{},将,替换成@后集合的遍历。

import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;

public class Demo01ArrayListEach {
    public static void main(String[] args) {
       ArrayList list = new ArrayList<>();
       Scanner sc = new Scanner(System.in);
        int num = sc.nextInt();
       System.out.println("需要" + num + "个随机数字");
        randomArrayList(list, num);
        System.out.println("================");
        printArrayList(list);
        System.out.println("================");
        // 打印集合的元素
        System.out.println(list);
        System.out.println("================");
        // 将替[]换成{},将,替换成@
        printArrayList2(list);
    }

    public static void  printArrayList(ArrayList list){
        for (int i = 0; i < list.size(); i++) {
            System.out.println("第" + (i+1) + "个元素:" + list.get(i));
        }
    }
    public static void randomArrayList(ArrayList list, int sc){
        Random randomAL = new Random();
        for (int i = 0; i < sc; i++) {
            list.add(randomAL.nextInt(20)+1);
        }
        for (int i = 0; i < list.size(); i++) {
            System.out.println("添加成功的第" + (i+1) + "元素为" + list.get(i));
        }
    }
    public static void  printArrayList2(ArrayList list){
        System.out.println("将替[]换成{},将,替换成@后集合的遍历结果:");
        System.out.print("{");
        for (int i = 0; i < list.size(); i++) {
            System.out.print(list.get(i)+ "@");
        }
        System.out.println("}");
    }
}

例题3

例题4
用一个大集合存入20个随机数字,然后筛选其中的偶数元素,放到小集合当中
要求使用自定义的方法来实现筛选

import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;

public class Demo01Num {
    public static void main(String[] args) {
        ArrayList bigList = new ArrayList<>();
        System.out.println("请输入随机数的个数");
        int x = new Scanner(System.in).nextInt();
        for (int i = 0; i < x; i++) {
            bigList.add(new Random().nextInt(50));
        }
        System.out.println(bigList);
        System.out.println("打印偶数的个数为:" + smarllArrayList(bigList).size() );
        System.out.println(smarllArrayList(bigList));

    }
    public static ArrayList smarllArrayList(ArrayList bigList){
        ArrayList smarllList = new ArrayList<>();
        for (int i = 0; i < bigList.size(); i++) {
            if (bigList.get(i) % 2 == 0){
                smarllList.add(bigList.get(i));
            }
        }
        return smarllList;
    }
}

例题4
String

java .long.String 类 代表字符串
API:Java 程序中的所有字符串字面值(abc)都作为此类的实例实现
其实就是说:程序当中所有的双引号字符串,都是String类的对象

字符串的特点:

  1. 字符串的内容永不改变【重点】
    2.  正是因为字符串不可改变,所以字符串是可以共享使用的
    3.  字符串效果上相当于是char[ ]字符数组,但是底层原理是byte[ ]字节数组

创建字符串的常见3+1种方式
三种构造方法:
public String ( ); 创建一个空白字符串,不含有任何内容
public String ( char[ ] array); 根据字符数组的内容,来创建对应的字符串
public String( byte[ ] array); 根据字节数组的内容,来创建对应的字符串
一种直接创建:
String str = "Hello";
注意:直接写上双引号,就是字符串对象

字符串常量池:程序当中直接写上的双引号字符串,就在字符串常量池中
对于基本类型来说,== 是进行数值的比较
对于引用类型来说,==是进行【地址值】的比较

常量池

==是进行对象的地址值比较,如果确实需要字符串的内容比较,可以使用两个方法
public boolean equals(Object obj): 参数可以是任何对象,只有参数是一个字符串并且内容相同的才会给true;否则返回false
注意事项:
1. 任何对象都能用Object进行接收
2. equals方法具有对称性,也就是 a.equals(b) 和 b.equals(a) 效果一样
3. 如果比较双方一个常量一个变量,推荐把常量字符串写在前面
推荐: "abc".equals(str) 不推荐: str.equals("abc")
public boolean equalsIgnoreCase(String str): 忽略大小写,进行内容比较

String str4 = null;
        System.out.println(str4.equals("abc"));
NullPointException 空指针异常
 String strA = "Java";
        String strB = "java";
        System.out.println(strA.equalsIgnoreCase(strB));
equalsIgnoreCase 不区分大小写

String 中 与获取相关的常用方法:
public int length( ):获取字符串当中含有的字符个数,拿到字符串长度。
public String concat ( String str):将当前字符串和参数字符串拼成为返回新的字符串值。
public char charAt ( int index):获取指定索引位置的单个字符。(索引从0开始)
public int indexOf ( String str ):查找参数字符串再本字符串当中首次出现的索引位置,如果没有则返回-1值
public String substring (int index) : 截取从参数位置一直到字符串末尾并返回新字符串。
public String substring (int begin, int end):截取从begin开始直到end结束中间的字符串
注意:[ begin, end)   包含左边不包含右边。
public char[ ] toCharArray( ):将当前字符串拆分为字符数组作为返回值
public byte[ ] getByte( ):获取当前字符串底层的字节数组
public String replace(CharSequence oldString, CharSequence newString):将所有出现的老字符串替换成新的字符串,返回替换之后的新字符串
public String[ ] split( String regex ): 按照参数的规则,将字符串切分成为若干部分(注意:切分英文的.需要使用\.才能够进行使用)

字符串的内容不变是因为String式引用类型,改变的是变量的地址值,并非其中的内容。

 public static void main(String[] args) {
        String str1 = "Java";
        String str2 = "World";
        System.out.println("第一个字符串的长度为:" + str1.length());

        System.out.println("拼接两个字符串:" + str1.concat(str2));

        System.out.println("第一个字符串的索引为3的字符:" + str1.charAt(3));

        System.out.println("a 在第一个字符串中的索引值为:" + str1.indexOf("a"));

        System.out.println("截取从索引值为1的字符串:" + str1.substring(1));

        System.out.println("截取从索引值1至索引值3的字符串:" + str1.substring(1,3));

        // 转换为字符数组
        char[] chars = "abc".toCharArray();
        for (int i = 0; i < chars.length; i++) {
            System.out.println(chars[i]);
        }
        // 转换为字节数组
        byte[ ] bytes = "abc".getBytes();
        for (int i = 0; i < bytes.length; i++) {
            System.out.println(bytes[i]);
        }
        // replace 替换字符
        String str3 = "How are you?";
        System.out.println(str3);
        str3 = str3.replace("o","*");
        System.out.println(str3);


        String str4 = "aaa.bbb.ccc";
        String[] array1 = str4.split("\\.");
        for (int i = 0; i < array1.length; i++) {
            System.out.println(array1[i]);
        }
    }

String常用方法打印结果

例题1:
写一个方法将{1,2,3}拼接成[word1#word2#word3]的格式输出

public static void main(String[] args) {
        int[] str1 ={1,2,3};
        System.out.println(strPritest(str1));
    }
    public static String strPritest(int[] str1){
        String strString = "[";
        for (int i = 0; i < str1.length; i++) {
            if (i == str1.length - 1){
                strString += "word" + str1[i] + "]";
            } else {
                strString += "word" + str1[i] + "#";
            }
        }
        return strString;
    }
image.png

static 关键字

static解释

一旦使用static修饰成员方法,那么这就成为了静态方法。静态方法不属于对象,而是属于类的。

如果没有static关键字,那么必须先创建对象,然后通过对象才能使用它。
如果有static关键字,那么不需要创建对象,直接就能通过类名称来使用它。

无论是成员变量,还是成员方法。如果有了static,都推荐使用类名称进行调用
静态变量:类名称.静态变量
静态方法:类名称.静态方法( )

注意事项:
1. 静态不能直接访问非静态
原因:因为在内存当中是【先】有的静态内容,【后】有的非静态内容
“先人不知道后人,后人知道先人”
2. 静态方法当中不能用this关键字
原因:this代表当前对象,通过谁调用的方法,谁就是当前对象。

public class Demo02Static {
    int num;
    static int numStatic;
    public static void staticMethod(){
        System.out.println("静态方法");
//        System.out.println(this); // 报错
//        System.out.println(num);  //报错
    }
}
static内存图
静态代码块

特点:当第一次用到本类的时,静态代码块执行唯一的一次。
静态内容总是优先于非静态,所以静态代码块比构造方法先执行。

静态代码块的典型用途:
用来一次性地对静态成员变量进行赋值。

Arrays

java.util.Arrays是一个与数组相关的工具类,里面提供了大量静态方法,用来实现数组常见的操作

public static String toString(数组):将参数数组变成字符串(按照默认格式 [元素1,元素2,元素3...])
public static void sort(数组):按照默认升序,从小到大对数组的元素进行排序
备注:

1. 如果是数组,sort默认按照升序从小到大
2. 如果是字符串,sort默认按照字母ASCII编码进行的升序(区分大小写)
3. 如果是自定义的类型,那么这个自定义的类需要有Comparable 或者 Comparator接口的支持。(今后学习)

import java.util.Arrays;

public class Demo01Arrays {
    public static void main(String[] args) {
        int[] ary = {1,2,3,4};
        String str = Arrays.toString(ary);
        System.out.println(str);
        int[] ary2 = {4,8,9,2,16,3};
        Arrays.sort(ary2);
        System.out.println(Arrays.toString(ary2));
        String[] strAry = {"ccc","aaa","zzz","BBB"};
        Arrays.sort(strAry);
        System.out.println(Arrays.toString(strAry));
    }
}
Arrays打印结果

例题1:
随机输入一组字母,升序后倒序打印

import java.util.Arrays;
import java.util.Scanner;

public class Demo01ArraysPractice {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("随机输入一组字符串:");
        String str = sc.next();
        System.out.println("升序后倒序打印:");
        char[] strChar = str.toCharArray();
        Arrays.sort(strChar);
        // .forr  递减循环
        for (int i = strChar.length - 1; i >= 0; i--) {
            System.out.print(strChar[i]);
        }
    }
}
例题1
Math

java.util.Math类是数学相关的工具类,里面提供了大量的静态方法,完成与数学运算相关的操作
public static double abs(double num):获取绝对值,有多种重载
public static double ceil(double num):向上取整
public static double floor(double num):向下取整
public static double round(double num):四舍五入
注意:
Math.PI代表近似的圆周率常量(double)

public class Demo03Math {
    public static void main(String[] args) {
        // 绝对值
        System.out.println(Math.abs(3.5));
        System.out.println(Math.abs(0));
        System.out.println(Math.abs(-3.5));
        System.out.println("=============================");
        // 向上取整
        System.out.println(Math.ceil(3.9));
        System.out.println(Math.ceil(3.1));
        System.out.println(Math.ceil(3.0));
        System.out.println("=============================");
        // 向下取整
        System.out.println(Math.floor(3.9));
        System.out.println(Math.floor(3.1));
        System.out.println(Math.floor(3.0));
        System.out.println("=============================");
        // 四舍五入
        System.out.println(Math.round(3.5));
        System.out.println(Math.round(3.4));
    }
}

Math常用方法

例题:
计算-10.8 ~ 5.9之间,绝对值大于6或者小于2.1的整数有多少个?

public class Demo04MathPractice {
    public static void main(String[] args) {
        double min = -10.8;
        double max = 5.9;
        int count = 0;

        for (int i = (int)min; i < max ; i++) {
            int abs = Math.abs(i);
            if (abs > 6 || abs < 2.1 ){
                count++;
            }
        }
        System.out.println(count);
    }
}
例题

继承

继承

定义父类的格式:(一个普通的类定义)
public class 父类名称{
// ...
}
定义子类的格式:
public class 子类名称 extends 父类名称{
// ...

在父子类的继承关系当中,如果成员变量重名,则创建子类对象时,访问有两种方式:
直接通过子类对象访问对象成员变量:
   等号左边是谁,就优先用谁,没有则向上找
间接通过成员方法访问成员变量:
   该方法属于谁,就优先用谁,没有则向上找
局部变量:   直接写成员变量名
本类的成员变量:this.成员变量名
父类的成员变量:super.成员变量名
注意事项:
无论成员方法还是成员变量,如果没有都是向上找父类,绝对不会向下找子类。

public class Fu {
    int numFu = 10;
    int num = 100;
}
public class Zi extends Fu {
    int numZi = 20;
    int num = 200;
    public void method(){
        int num = 300;
        System.out.println(num); // 局部变量
        System.out.println(this.num); // 成员变量
        System.out.println(super.num); // 父类变量

    }
}
public class DemoExtendsField {
    public static void main(String[] args) {
        Fu fu = new Fu();
        System.out.println(fu.numFu);

        Zi zi = new Zi();
        System.out.println(zi.numZi);
        System.out.println(zi.numFu);
        System.out.println(zi.num);
        zi.method();
    }
}
继承
重写(Override)

概念: 在继承关系当中,方法的名称一样,参数列表也一样
重写(Override):方法的名称一样,参数列表【也一样】覆盖、覆写
重载(Overload):方法的名称一样,参数列表【不一样】

方法的覆盖重写特点:创建的是子类对象,则优先用子类方法
方法覆盖重写的注意事项:
1. 必须保证父子类之间方法的名称相同,参数一致
@Override:写在方法前面,用来检测是不是有效的正确覆盖重写。(这个注解就算不写,只要满足要求,也是正确的方法覆盖重写)
2. 子类方法的返回值必须【小于等于】父类方法的返回值范围
小扩展:java.lang.Object类是所有类的公共最高父类(Object),java.lang.String 就是Object的子类

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

        System.out.println("子类方法执行");
    }
    @Override
    public void method(){
        System.out.println("子类重名方法执行");
    }
}
举例说明继承

super:继承中的构造方法:

继承关系中:父子类构造方法的访问特点
1. 子类构造方法当中有一个默认隐含的super()调用,所以一定先调用父类的构造方法
2. 子类构造可以通过super关键字来调用父类重载构造
3. super的父类构造调用,必须是子类构造方法的第一个语句,不能一个子类构造调用多次super构造。
子类必须调用父类构造方法,不写则赠送super( );写了则用写的指定的super调用,super只能有一个,还必须是第一个。
super关键字的三种用法:
1. 在子类的成员方法中,访问父类的成员变量。
2. 在子类的成员方法中,访问父类的成员方法。
3. 在子类的构造方法中,访问父类的构造方法。

public class Fu {
    int num = 20;
    public Fu(){
        System.out.println("");
    }
    public void method(){

    }
}
public class Zi extends Fu {
    int num = 20;
    
    public Zi(){
        super();
    }
    
    public void methodZi(){
        System.out.println(super.num);
    }

    public void method(){
        super.method();
        System.out.println("子类方法");
    }

}

this关键字

super关键字用来访问父类内容,this关键字用来访问本类内容;
用法:
1. 在本类的成员方法中,访问本类的成员变量
2. 在本类的成员方法中,访问本类的另一个成员方法
3. 在本类的构造方法中,访问本类的另一个构造方法
在第三种用法当中要注意:
this( ...)调用也必须是构造方法的第一个语句,唯一 一个。
super和this两种构造调用,不能同时使用。

public class Zi extends Fu {
   int num = 20;
   public Zi(){
       this(100); // 在本类的无参构造方法中调用有参构造方法
       System.out.println("无参构造方法");
       
   }
   public Zi(int A){
       System.out.println("有参构造方法");
   }
   public void showNum(){
       int num = 10;
       System.out.println(num); // 局部变量 10
       System.out.println(this.num); //成员变量 20
       System.out.println(super.num);//父类成员变量30
   }
   public void methodA(){
       System.out.println("AAAA");
   }
   public void methodB(){
       this.methodA(); // 在本类的成员方法中调用成员方法
       super.method(); // 在本类的成员方法中调用父类的成员方法
       System.out.println("BBB");  
   } 

}
image.png
继承的特点
特点

抽象方法

抽象方法

抽象方法:加上abstract关键字,然后去掉大括号,直接分号结束
抽象类:抽象方法所在的类,必须是抽象类才行。在class之前写上abstract
如果使用抽象类和抽象方法:
1. 不能直接创建new抽象类对象
2. 必须用一个子类来继承抽象父类
3. 子类必须覆盖重写抽象类父类当中所有的抽象方法
覆盖重写:子类去掉抽象方法abstract关键字,然后补上方法体大括号
4. 创建子类对象进行使用
注意事项:


image.png
例题1:一个群主给几个人发红包
例题1
package cn.itcast.redMoney;

public class User {
    private String name;
    private int money;

    public User() {
    }

    public User(String name, int money) {
        this.name = name;
        this.money = money;
    }

    public String getName() {
        return name;
    }

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

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }
    public void show(){
        System.out.println("我叫:" + name + ",我有多少钱:" + money);
    }
}
package cn.itcast.redMoney;

import java.util.ArrayList;

public class Manager extends User {
    public Manager() {
    }

    public Manager(String name, int money) {
        super(name, money);
    }

    public ArrayList send(int totalMoney, int count){
        ArrayList redList = new ArrayList<>();
        int redMoney = super.getMoney();
        if (totalMoney > redMoney){
            System.out.println("余额不足");
            return redList;
        }
        // 重新设置群主的余额
        super.setMoney(redMoney - totalMoney);
        int avg = totalMoney / count;
        int leftMoney = totalMoney % count;
        for (int i = 0; i < count-1; i++) {
            redList.add(avg);
        }
        int listRed = avg + leftMoney;
        redList.add(listRed);
        return redList;
    }
}
package cn.itcast.redMoney;

import java.util.ArrayList;
import java.util.Random;

public class Member extends User{
    public Member() {
    }

    public Member(String name, int money) {
        super(name, money);
    }
    public void receive(ArrayList list){
        int index = new Random().nextInt(list.size());
        int delta = list.remove(index);
        int money = super.getMoney();
        super.setMoney(money + delta);
    }
}
package cn.itcast.redMoney;

import java.util.ArrayList;

public class MainRedPacket {
    public static void main(String[] args) {
        Manager manager = new Manager("群主",100);

        Member one = new Member("成员A",0);
        Member two = new Member("成员B",0);
        Member three = new Member("成员C",0);

        manager.show();
        one.show();
        two.show();
        three.show();
        System.out.println("========================");

        ArrayList redList = manager.send(20,3);
        one.receive(redList);
        two.receive(redList);
        three.receive(redList);
        manager.show();
        one.show();
        two.show();
        three.show();
    }
}
红包案例

接口:Interface

image.png

接口就是多个类的公共规范
接口是一种引用类型,最重要的内容就是其中的:抽象方法。
接口是一种引用数据类型,最重要的内容就是其中的抽象方法
如何定义一个接口的格式:
public interface 接口名称{
 // 接口内容
}
备注:换成了关键字interface之后,编译生成的字节码文件仍然是java.util.class

如果是Java 7,那么接口中可以包含的内容有:
1. 常量
2. 抽象方法
3. 默认方法
4. 静态方法
5. 私有方法

抽象方法

格式:
public abstract 返回值类型 方法名称 ( 参数列表 );
注意:
1. 接口当中的抽象方法,修饰符必须是两个固定的关键字:public abstract
2. 这两个关键字修饰符,可以选择性的省略
3. 方法的三要素,可以随意定义
接口的使用:
1. 接口不能直接使用,必须有一个类来实现该接口
格式:
public class 实现类名称 implements 接口名称{
  // ...

2. 接口的实现类必须覆盖重写接口中所有的抽象方法
去掉abstract关键字,加上方法体大括号
3. 创建实现类的对象,进行使用
注意事项:
如果实现类并没有覆盖重写接口中所有的抽象方法,那么这个实现类自己就必须是抽象类

public interface MyInterfaceAbstract {
    public abstract void methodAbs1();
    abstract void methodAbs2();
    public void methodAbs3();
    void methodAbs4();
}
默认方法:

格式:
public default 返回值类型 方法名称(参数列表){
 // 方法体

注意:实现了接口的升级

public interface   MyInterfaceDefault {
        public abstract void methodAbs();
        // 新添加的抽象方法: 默认方法
        public default void methodDefault(){
                System.out.println("添加的默认方法");
        }

}
public class MyInterfaceDefaultA implements MyInterfaceDefault{
    @Override
    public void methodAbs() {
        System.out.println("实现了方法 AAA");
    }
}
public class MyInterfaceDefaultB implements MyInterfaceDefault{
    @Override
    public void methodAbs() {
        System.out.println("实现了 BBB");
    }
}
public class Demo02Iterface {
    public static void main(String[] args) {
        MyInterfaceDefaultA a = new MyInterfaceDefaultA();
        a.methodAbs();
        a.methodDefault();

        System.out.println("======================");

        MyInterfaceDefaultB b = new MyInterfaceDefaultB();
        b.methodAbs();
        b.methodDefault();
    }
}
默认方法
public class MyInterfaceDefaultB implements MyInterfaceDefault{
    @Override
    public void methodAbs() {
        System.out.println("实现了 BBB");
    }

    @Override
    public void methodDefault() {
        System.out.println("重写了默认方法");
    }
}
默认方法也可重写
静态方法:

将abstract 或者 default 换成 static即可,带上方法体
格式:
public static 返回值类型 方法名称(参数列表){
 // 方法体

注意:
不能通过接口实现类的对象来调用接口当中的静态方法
调用方法:
格式:
接口名称.静态方法名(参数);

public interface MyInterfaceStatic {
    public static void methodStatic(){
        System.out.println("静态方法");
    }
}
public class MyInterfaceStaticimpl implements MyInterfaceStatic{

}
public class Demo03Interface {
    public static void main(String[] args) {
        MyInterfaceStatic.methodStatic();
    }
}
静态方法
私有方法

用来解决多个默认方法之间重复代码问题

抽取一个公共方法,用来解决两个默认方法之间重复代码的问题(该方法不能让实现类使用,应该是私有的)
1. 格式:
private 返回值类型 方法名称(参数列表){
 // 方法体

2. 静态私有方法,解决多个静态方法之间重复代码问题
格式:
private static 返回值类型 方法名称(参数列表){
 // 方法体

私有方法的使用:

public interface MyInterfacePrivateA {
    public default void methodDefaultA(){
        System.out.println("默认方法1");
        methodCommon();
    }

    public default void methodDefaultB(){
        System.out.println("默认方法2");
        methodCommon();
    }
    private void methodCommon(){
        System.out.println("AAA");
        System.out.println("BBB");
        System.out.println("CCC");
    }
}

public interface MyInterfacePrivateB {
    public static void methodStaticA(){
        System.out.println("静态方法1");
        methodStaticCommon();
    }

    public static void methodStaticB(){
        System.out.println("静态方法2");
        methodStaticCommon();
    }
    private static void methodStaticCommon(){
        System.out.println("AAA");
        System.out.println("BBB");
        System.out.println("CCC");
    }
}

public class MyInterfacePrivateADefault implements MyInterfacePrivateA{
    @Override
    public void methodDefaultA() {
        MyInterfacePrivateA.super.methodDefaultA();
    }
}
public class Demo4Iterface {
    public static void main(String[] args) {
        MyInterfacePrivateB.methodStaticA();
        MyInterfacePrivateB.methodStaticB();
        MyInterfacePrivateADefault de = new MyInterfacePrivateADefault();
        de.methodDefaultA();
    }
}
私有方法的使用
接口中的常量

接口当中也可以定义成员变量,但是必须使用public static final 三个关键字修饰。
public static final 数据类型 常量名称 = 数据值;

一旦赋值不可修改(final 修饰 说明不可改变 )

注意事项:
1. 接口当中的常量,可以省略public static final
2. 接口当中的常量,必须进行赋值,不能不赋值。
3. 接口中常量的名称,使用完全大写的字母,用下划线进行分割(推荐命名规则)
接口中常量的使用  (接口.常量名称)

public interface MyInterfaceConst {
    public static final int NUM = 10;
}
public class Demo05Interface {
    public static void main(String[] args) {
        System.out.println(MyInterfaceConst.NUM);
    }
}
接口.常量
接口小结:

接口汇总

接口使用的注意事项总结
1. 接口中没有静态代码块或者构造方法
2. 一个类的直接父类是唯一的,但是一个类可以同时实现多个接口
格式:
public class 实现类 implements 接口类A,接口类B{
 // 覆盖重写所有的抽象方法

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

public abstract class MyInterfaceAbstract implements MyInterfaceA,MyInterfaceB {
    @Override
    public void methodA() {

    }

    @Override
    public void methodB() {

    }
}

5. 如果实现类所实现的多个接口当中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖重写
6. 一个类如果直接父类当中的方法,和接口当中的默认方法产生了冲突,优先使用父类当中的方法(继承优先于接口实现)

public class Fu {
    public void method(){
        System.out.println("父类的方法");
    }
}
public class Zi extends Fu implements MyInterfaceImpl{

}
public interface MyInterfaceImpl {
    public default void method(){
        System.out.println("接口的默认方法");
    }
}
public class Demo01Interface {
    public static void main(String[] args) {
        Zi zi = new Zi();
        zi.method();
    }
}
默认方法冲突优先选择父类的方法
接口与接口之间的多继承关系

1. 类与类之间是单继承的,直接父类只有一个
2. 类与接口之间是多实现的,一个类可以实现多个接口
3. 接口与接口之间是多继承的。
注意事项:
1. 多个父接口当中的抽象方法重复没有关系,不会报错
2. 多个父接口当中的默认方法如果重复,那么子接口必须进行默认方法的覆盖重写【必须带着default关键字】

public interface MyInterfaceA {
    public abstract void methodA();
    public abstract void methodCommon();
    public default void methodDefault(){
        System.out.println("AAAA");
    }

}
public interface MyInterfaceB {
    public abstract void methodB();
    public abstract void methodCommon();
    public default void methodDefault(){
        System.out.println("BBBB");
    }
}
public interface MyInterface extends MyInterfaceA, MyInterfaceB{

    public abstract void method();

    @Override
    default void methodDefault() {
        MyInterfaceA.super.methodDefault();
    }
}
public class MyInterfaceImpl implements MyInterface{
    @Override
    public void method() {
        System.out.println("重写覆盖自己的方法");
    }

    @Override
    public void methodA() {
        System.out.println("重写覆盖自己的方法");
    }

    @Override
    public void methodB() {
        System.out.println("重写覆盖自己的方法");
    }

    @Override
    public void methodCommon() {
        System.out.println("重写覆盖自己的方法");
    }
}

多态

多态的特点

父类引用指向子类对象
父类名称 对象名 = new 子类名称();
接口名称 对象名 = new 实现类名称();
访问成员变量的两种方式:
1. 直接通过对象名称访问成员变量,看等号左边是谁,优先用谁,没有则向上找。
2. 直接通过成员方法访问成员变量,看该方法属于谁,优先用谁,没有则向上查找
成员方法的访问规则:
1. 看new的是谁,就优先用谁,没有则向上找
2. 编译看左边,运行看右边。
成员方法和成员变量对比
成员变量:编译看左边,运行还看左边
成员方法:编译看左边,运行看右边
多态的优点无论右边new为哪个子类对象,等号左边调用的方法都不会变化。
1. 对象的向上转型一定是安全的,对象一旦向上转型为父类,无法调用子类特有的内容;

父类名称 对象名 = new 子类名称();

2. 对象的向下转型
子类名称 对象名 = (子类名称) 父类对象
ClassCastException // 向下非原本的new 子类名称显示的类异常出错
安全的向下转型方式:
对象 instanceof 类名称
得到boolean值,判断前面的对象能不能当做后面类型的实例

public abstract class Animal {
    public abstract void eat();
}
public class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
    public void catchMouse(){
        System.out.println("猫捉老鼠");
    }
}
public class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }
    public void watchHouse(){
        System.out.println("狗看家");
    }
}
public class Demo01Main {
    public static void main(String[] args) {
        Animal animal = new Cat();
        animal.eat();

        giveMeAPet(new Dog());
    }
    public static void giveMeAPet(Animal animal){
        if(animal instanceof Dog) {
            Dog dog = (Dog) animal;
            dog.watchHouse();
        }
        if(animal instanceof Cat) {
            Cat cat = (Cat) animal;
            cat.catchMouse();
        }
    }
}

image.png

例题1:

public interface Usb {
    public abstract void open();
    public abstract void close();
}
public class Notebook  {
    public void powerOn(){
        System.out.println("打开电脑");
    }
    public void powerOff(){
        System.out.println("关闭电脑");
    }
    public void useDevice(Usb usb){
        usb.open();
        // 向下转型
        if(usb instanceof Mouse){
            Mouse mouse = (Mouse) usb;
            mouse.click();
        } else if(usb instanceof Keyboard){
            Keyboard keyboard = (Keyboard) usb;
            keyboard.type();
        }
        usb.close();
    }
}
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("点击");
    }
}
public class Keyboard implements Usb{
    @Override
    public void open() {
        System.out.println("打开键盘");
    }

    @Override
    public void close() {
        System.out.println("关闭键盘");
    }
    public void type(){
        System.out.println("输入");
    }
}
public class Demo01Main {
    public static void main(String[] args) {
        Notebook notebook = new Notebook();
        notebook.powerOn();
        // 向上转型
        Usb usbMouse = new Mouse();
        notebook.useDevice(usbMouse);

        // 匿名方法调用
        //notebook.useDevice(new Keyboard());

        // 向下转型调用
        Keyboard keyboard = new Keyboard();  // 没有使用多态的方法
        notebook.useDevice(keyboard);

        notebook.powerOff();

    }
}
例题1

final

最终的,不可改变的
常用的四种方法:
1. 可以用来修饰一个类
2. 可以用来修饰一个方法
3. 可以用来修饰一个局部变量
4. 可以用来修饰一个成员变量

final修饰类

此类不能有任何子类,一个类如果是final,其中所有的成员方法都无法进行覆盖重写,

格式:
public final class 类名称{
  // ...

final修饰方法

最终方法,不能被覆盖重写。abstract 关键字和final关键字不能同时使用,矛盾
abstract:必须要全部覆盖重写
final:不能被覆盖重写
格式:
修饰符 final class 方法名称(参数列表){
  // ...

final修饰局部变量

一次赋值终生不变。
基本类型:指的是数据不可变
引用类型:指的是地址不可变

public class Student {
    private String name;
    public Student() {
    }
    public Student(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
public class Demo01Final {
    public static void main(String[] args) {
        int num = 10;
        System.out.println(num);
        final int num1 = 20;
        System.out.println(num1);
        // 报错。final关键字修饰基本类型的的局部变量不可变
        // num2 = 30;

        // 不使用final stu是两个不同的地址
        Student stu = new Student("李白");
        System.out.println(stu.getName() + stu);
        stu = new Student("杜甫");
        System.out.println(stu.getName() + stu);
        
        // 使用fina,l引用类型的地址不发生改变,但是地址所存储的内容可以进行修改。
        final Student stu1 = new Student("张三");
        System.out.println(stu1.getName() + stu1);
        stu1.setName("李四");
        System.out.println(stu1.getName() + stu1);
    }
}
image.png
final修饰成员变量

1. 由于成员变量有默认值,所以使用了final之后必须手动赋值,不会再提供默认值。
2. 对于final的成员变量,要么直接赋值,要么通过构造方法赋值,二者选其一
3. 必须保证类当中所有重载的构造方法,都最终会对final的成员变量进行赋值。

public class Person {
    private final String name/* = "周瑜"*/ ;

    public String getName() {
        return name;
    }

    public Person(String name) {
        this.name = name;
    }

    public Person() {
        name = "小乔";
    }
}

四种修饰符的总结

修饰符访问范围比较

内部类:

分类:
1.成员内部类
2.局部内部类(包含匿名内部类)
成员内部类定义格式:
修饰符 class 外部类名称 {
  修饰符 class 内部类名称{
  // ...

   // ...
}
注意: 内用外,随意访问,外用内,需要内部类对象
如何使用成员内部类:两种方法:
1. 间接方式:在外部类的方法当中,使用内部类;然后main只是调用外部类的方法。
2. 直接方式:
类名称 对象名 = new 类名称();
【外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();】

public class Body {
    public class Heart{
        public void beat(){
            System.out.println("砰砰砰");
            System.out.println(name);
        }
    }
    private String  name ;

    public void mehtodBody() {
        Heart heart = new Heart();
        heart.beat();
    }
    public Body() {
    }

    public Body(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
public class Demo01Main {
    public static void main(String[] args) {
        // 间接调用内部类的方法 :
        // 调用外部类的方法,从方法中调用创建内部类对象从而调用内部类的方法
        Body body = new Body();
        body.setName("李白");
        body.mehtodBody();
        
        System.out.println("===========");
        // 直接调用内部类的方法
        Body.Heart body1 = new Body().new Heart();
        body1.beat();
    }
}
image.png
public class Outer {
    int num = 10; // 外部类成员变量
    public class Inner{
        int num = 20;  // 内部类成员变量
        public void methodInner(){
            int num = 30; // 内部类的局部变量
            System.out.println(num);            // 内部类的局部变量
            System.out.println(this.num);       // 内部类的成员变量
            System.out.println(Outer.this.num); // 外部类的成员变量
        }
    }
}
public class Demo02Main {
    public static void main(String[] args) {
        // 直接方法调用内部类中的方法 解决重名变量的问题 外部类.this.变量名
        Outer.Inner outer = new Outer().new Inner();
        outer.methodInner();
    }
}

成员内部类

局部内部类
如果一个类定义在一个方法内部的,那么这就是一个局部内部类
“局部”:只有当前所属的方法才能使用它。除了这个方法外部就不能用了
定义格式:
修饰符 class 外部类名称{
  修饰符 返回值类型 外部类方法名称(参数列表){
    class 局部内部类名称{
      // ...
    }
  }

public class Outer {
    public void methodOuter(){
        class Inner{
            int  num = 10;
            public  void  methodInner(){
                System.out.println(num);
            }
        }
        Inner inner = new Inner();
        inner.methodInner();
    }
}
public class Demo03Main {
    public static void main(String[] args) {
        // 局部内部类中方法的调用需要在外部类的方法中创建局部内部类对象,通过对象调用内部类的方法
        Outer outer = new Outer();
        outer.methodOuter();
    }
}

类的权限修饰符:

public > protected > (default) > private
定义一个类,权限修饰符规则:
1. 外部类:public / (default)
2. 成员内部类: public / protected / (default) / private
3. 局部内部类:什么都不写

局部内部类:如果希望访问所在方法的局部变量,那么这个局部变量必须是【有效的final修饰】
原因:
1. new出来的对象在堆内存当中
2. 局部变量是跟着方法走的,在栈内存中
3. 方法运行结束之后,立刻出栈,局部变量就会立刻消失
4. 但是new出来的对象会在堆当中持续存在,直到垃圾回收消失

匿名内部类:

如果接口的实现类(或者是父类的子类),只需要使用唯一的一次
那么这种情况下可以省略实现类,使用匿名内部类

匿名内部类的定义格式:
接口名称 对象名 = new 接口名称 () {
  // 覆盖重写接口的所有抽象方法
};

public interface MyInterface {
    public abstract void method();
}
public class MyInterfaceImpl implements MyInterface{

    @Override
    public void method() {
        System.out.println("实现类覆盖重写了接口类的方法");
    }
}
public class DemoMain {
    public static void main(String[] args) {
        MyInterface obj = new MyInterfaceImpl();
        obj.method();
        System.out.println("===============");
        // 匿名内部类
        MyInterface myInterface = new MyInterface() {
            @Override
            public void method() {
                System.out.println("覆盖重写了接口类的方法");
            }
        };
        myInterface.method();
    }
}

image.png

对格式 “ new 接口名称(){...};” 进行解析:
1. new代表创建对象的动作
2. 接口名称就是匿名内部类需要实现哪个接口
3. {...}这才是匿名内部类的的内容
注意事项:
1. 匿名内部类,在创建对象的时候,只能使用唯一的一次,如果希望多次穿件对象,而且类的内容一样的话,那么必须使用单独定义的实现类。
2. 匿名对象,在调用方法的时候,只能调用唯一一次
如果希望同一个对象,调用多次方法,那么必须给对象起个名字。
3. 匿名内部类是实现了【实现类/子类】,匿名对象是省略了【对象名称】匿名内部类和匿名对象不是一回事

public interface MyInterface {
    void method();
    void method2();
}
public class DemoMain {
    public static void main(String[] args) {
        MyInterface obj = new MyInterfaceImpl();
        obj.method();
        System.out.println("===============");
        // 匿名内部类
        MyInterface myInterface = new MyInterface() {
            @Override
            public void method() {
                System.out.println("覆盖重写了接口类的方法111-A");
            }

            @Override
            public void method2() {
                System.out.println("覆盖重写了接口类的方法222-A");
            }
        };
        myInterface.method();
        myInterface.method2();
        System.out.println("============");
        // 既是匿名对象,又是匿名内部类
        new MyInterface() {
            @Override
            public void method() {
                System.out.println("覆盖重写了接口类的方法111-B");
            }

            @Override
            public void method2() {
                System.out.println("覆盖重写了接口类的方法222-B");
            }
        }.method();
    }
}
匿名内部类
类作为成员变量
public class Weapon {
    private String code;

    public Weapon() {
    }

    public Weapon(String code) {
        this.code = code;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }
}
public class Here {
    private String name;
    private int age;
    private Weapon weapon;

    public Here() {
    }

    public Here(String name, int age, Weapon weapon) {
        this.name = name;
        this.age = age;
        this.weapon = weapon;
    }

    public void attack(){
        System.out.println("年龄为" + age + "的" + name + ",使用" + weapon.getCode() + "攻击敌人");
    }
    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 Weapon getWeapon() {
        return weapon;
    }

    public void setWeapon(Weapon weapon) {
        this.weapon = weapon;
    }
}
public class DemoMain {
    public static void main(String[] args) {
        Here hero = new Here();
        hero.setName("盖伦");
        hero.setAge(20);

        // 穿件一个武器对象
        Weapon weapon = new Weapon("多兰剑");
        hero.setWeapon(weapon);

        hero.attack();
    }
}
image.png
接口作为成员变量
public interface Skill {
    void use(); // 释放技能的抽象方法
}
public class SkillImpl implements Skill{

    @Override
    public void use() {
        System.out.println("biu~biu~biu~");
    }
}

public class Hero {
    private String name; // 英雄的名称
    private Skill skill; // 英雄的技能

    public Hero() {
    }

    public Hero(String name, Skill skill) {
        this.name = name;
        this.skill = skill;
    }

    public void attack(){
        System.out.println("我叫" + name + ",开始释放技能");
        skill.use(); // 成员调用接口的方法
        System.out.println("技能完成");
    }
    public String getName() {
        return name;
    }

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

    public Skill getSkill() {
        return skill;
    }

    public void setSkill(Skill skill) {
        this.skill = skill;
    }
}
public class DemoMain {
    public static void main(String[] args) {
        Hero hero = new Hero();
        hero.setName("艾希");

        // 设置英雄的技能
        // 使用单独定义的实现类来实现接口的方法
        hero.setSkill(new SkillImpl());
        hero.attack();
        System.out.println("==================");
        // 使用匿名内部类实现接口的方法
        Skill skill = new Skill(){

            @Override
            public void use() {
                System.out.println("biu~biu~biu~");
            }
        };
        hero.setSkill(skill);
        hero.attack();

        System.out.println("===============");
        // 使用既是匿名方法又是匿名内部类的方法实现接口的方法
        hero.setSkill(new Skill() {
            @Override
            public void use() {
                System.out.println("pilipala~");
            }
        });
        hero.attack();
    }
}
image.png
接口作为方法的返回值和参数
import java.util.ArrayList;
import java.util.List;

public class DemoInterface {
    public static void main(String[] args) {
        List list = new ArrayList<>();
        List result = addName(list);
        for (int i = 0; i < result.size(); i++) {
            System.out.println(result.get(i));
        }
    }
    public static List addName(List list){
        list.add("李白");
        list.add("杜甫");
        list.add("张三");
        list.add("李四");
        return list;
    }
}
image.png

你可能感兴趣的:(Java 基础知识学习2)