Java基础学习——第四章 面向对象编程(上)

Java基础学习——第四章 面向对象编程(上)

一、类与对象(面向对象的两个要素)

1. Java面向对象的三条主线

  1. 类及类的成员:属性、方法、构造器;代码块、内部类
  2. 面向对象的三大特征:封装性、继承性、多态性、(抽象性)
  3. 其他关键字:this、super、static、final、abstract、interface、package、import等

2. 类和对象的概念

  1. :是对==一类事物的描述,是抽象的==、概念上的定义
  2. 对象:是实际存在的该类事物的==具体的个体,因而也称为实例==,对象是通过类new出来的
  3. 面向对象程序设计的重点就是设计类
  4. 设计类,其实就是设计==类的成员==:属性、方法、构造器;代码块、内部类

3. 理解“万事万物皆对象”

  1. Java将功能、结构等封装到类中,通过类的实例化,来调用具体的功能和结构
  2. 涉及到Java与前端的Html、后端的数据库交互时,都体现为类和对象

4. 类的成员之:属性和方法

  1. 属性:类中的成员变量(属性 = 成员变量 = field = 域或字段)
  2. 方法:类中的成员方法(方法 = 成员方法 = 函数 = method)

5. 类和对象的使用(基本步骤)

  1. 创建类,设计类的成员(如属性和方法)
  2. 创建类的对象 = 类的实例化 = 实例化类(通过new的方式)
  3. 对象的使用(调用对象的结构):属性(“对象.属性”)、方法(“对象.方法”
import java.util.Scanner;

//测试类
public class Day08_PersonTest {
    public static void main(String[] args) {

        //********************* 创建类Person的第一个对象 = 类的实例化 = 实例化类(new)
        Person p1 = new Person();
        //创建Scanner类的对象scan
        Scanner scan = new Scanner(System.in);
        //创建数组
        String[] arr = new String[2];

        //********************* 调用对象的结构:属性、方法
        //调用属性:"对象.属性"
        //在Person类中没有给name属性(成员变量)赋值,输出String类型变量的初始化值
        System.out.println(p1.name); //null
        //在Person类中已经给age属性(成员变量)赋过值了
        System.out.println(p1.age); //1
        //给对象的属性赋值
        p1.name = "Tom";
        p1.isMale = true;

        //调用方法:"对象.方法"
        p1.eat();
        p1.sleep();
        p1.talk("Chinese"); //"Chinese"传给了talk方法的language变量

        //********************* 创建类Person的第二个对象
        Person p2 = new Person();
        System.out.println(p2.name); //null

        //********************* 创建类Person的第三个对象
        //将p1中存放的对象地址值赋给了另一个引用类型变量p3,此时p1和p3共同指向堆空间中同一个对象实体
        Person p3 = p1;
        System.out.println(p3.name); //Tom
        p3.age = 10;
        System.out.println(p1.age); //10
    }
}

//创建类
class Person {
    //属性
    String name;
    int age = 1;
    boolean isMale;

    //方法
    public void eat() {
        System.out.println("人可以吃饭");
    }

    public void sleep() {
        System.out.println("人可以睡觉");
    }

    public void talk(String language) {
        System.out.println("人可以说话,使用的是:" + language);
    }
}

6. 对象的内存解析

Person p1 = new Person();
  • p1是Person类的对象的引用类型变量,p1的值 = 指向堆空间中对象实体的地址值
  • 引用类型变量p1声明在main()方法中,方法体内部声明的变量都是局部变量,故存放在栈空间中
  • 创建Person类时声明的三个属性name、age、isMale都是成员变量(方法体外,类体内声明的变量),存放在堆空间中。堆空间中的数组实体存放的是各个元素,而堆空间中的对象实体存放的是各个属性
  • 属性age在创建类时赋的初始值是1;属性name和isMale在创建类时未赋值,故进行相应类型变量的初始化:boolean类型变量isMale的初始化值是false;属性name是String类的对象的引用类型变量,故初始化值是null
p1.name = "Tom";
p1.isMale = true;
  • 给对象的属性赋值。注意,属性name的值 = 指向方法区字符串常量池中字符串对象"Tom"的地址值
Person p2 = new Person();
System.out.println(p2.name);
  • 因为引用类型变量p2指向的对象是new出来的,故在堆空间中重新开辟了一块内存空间存放新的对象实体
    此时p1和p2中存放的是不同的地址值,分别指向堆空间中两个相互独立的对象实体
  • 如果创建了一个类的多个对象,则每个对象都拥有一套独立的类的属性(非static的)
    如果我们修改其中一个对象某个属性A的值,并不会影响另一个对象的属性A的值
Person p3 = p1;
System.out.println(p3.name); //Tom
p3.age = 10;
System.out.println(p1.age); //10
  • 将引用类型变量p1中存放的地址值赋给另一个引用类型变量p3(在方法内声明的局部变量,存放在栈中),p1和p3共同指向堆空间中同一个对象实体。此时只是新声明了一个引用类型变量,而不是新创建了一个对象
    在这里插入图片描述

7. 匿名对象的使用

  1. 定义:创建(new)对象时,没有显式的将地址值赋给一个引用类型变量(变量名)
  2. 特点:匿名对象只能调用一次
  3. 使用:将匿名对象传给方法的形参,此时形参的值为该匿名对象在堆空间中的地址值
public class Day09_InstanceTest {
    public static void main(String[] args) {
        Phone p = new Phone();
        p.price = 1999;
        p.showPrice(); //手机的价格为:1999

        //匿名对象的特征
        new Phone().price = 1999;
        new Phone().showPrice(); //手机的价格为:0

        //匿名对象的使用
        PhoneMall mall = new PhoneMall();
        //将Phone类型的匿名对象传给show方法的形参,此时形参的值为该匿名对象在堆空间中的地址值
        mall.show(new Phone());
    }
}

class Phone {
    int price; //价格

    public void showPrice() {
        System.out.println("手机的价格为:" + price);
    }
}

class PhoneMall {

    //这里的形参phone是Phone类的对象实体的引用类型变量
    public void show(Phone phone) {
        System.out.println(phone); //形参phone的值为对象实体在堆空间中的地址值
        phone.showPrice();
    }
}

二、类的成员之一:属性(成员变量)

1. 属性(成员变量) vs 局部变量

在这里插入图片描述

1.1 相同点
1.1.1 定义变量的格式相同

数据类型 变量名 = 变量值;

1.1.2 先声明,后使用
1.1.3 变量都有其对应的作用域
1.2 不同点
1.2.1 在类中声明的位置不同
  • 属性(成员变量): 在方法(函数)体外,类体内声明的变量
    实例变量:不以static修饰,需要通过对象来访问
    类变量(静态变量):以static修饰,表示是"静态"的,不需要通过实例化一个类的对象来访问
  • **局部变量:**在方法(函数)体内部声明的变量
    形参:方法、构造器中定义的变量
    方法局部变量:在方法内定义
    代码块局部变量:在代码块内定义
1.2.2 权限修饰符不同
  • **属性(成员变量):**可以在声明属性时,指明其权限修饰符
    Java规定的4种权限修饰符:public、private、缺省(不写)、protected
  • **局部变量:**不可以使用权限修饰符
1.2.3 默认初始化值不同
  • **属性(成员变量):**类的属性,根据其类型,都有默认初始化值
    整型(byte、short、int、long):0
    浮点型(float、double):0.0
    字符型(char):0或’\u0000’(表示ASCII码为0的字符null,而不是字符’0’)
    布尔型(boolean):false
    引用数据类型(如类、数组、接口等):null
    在这里插入图片描述

  • **局部变量:**没有默认初始化值,因此我们在调用局部变量之前,一定要显式赋值。
    特别的,形参在调用时赋值即可(如talk方法中的language形参,只需在调用方法时给形参传递一个值即可)

1.2.4 在内存空间中加载的位置不同
  • **属性(成员变量):**堆空间(非static)
  • **局部变量:**栈空间
class User {
    //********************* 属性(成员变量)
    //实例变量:不以static修饰,需要通过对象来访问
    public String name; //public:公有的,可以在类,子类及类的外部使用;
    private int age; //private:私有的,只能在类中使用,不能在子类及类的外部使用;
    protected boolean isMale; //protected:受保护的,可以在类及子类中使用,不能在类的外部使用;

    //********************* 局部变量
    //形参:方法、构造器中定义的变量
    public void talk(String language) { //language:形参
        System.out.println("我们使用" + language);
    }

    //方法局部变量:在方法内定义的变量
    public void eat() {
        String food = "披萨"; //food:形参
    }
}

2. 属性(成员变量)赋值的先后顺序

  1. 默认初始化值
  2. 显式初始化值(在类中声明对象时即赋一个初始化值)
  3. 构造器中初始化
  4. 通过"对象.方法"和"对象.属性"的方式赋值

三、类的成员之二:方法

方法:描述类应该具有的功能
比如Math类的sqrt()方法;Scanner类的nextXxx()方法;Arrays类的sort()方法等

1. 方法的声明

权限修饰符 返回值类型 方法名(形参列表) {
	方法体
}
//此外static、final、abstract也可以用来修饰方法

在这里插入图片描述

//客户类
class Customer {
    //*************属性
    String name;
    int age;
    boolean isMale;
    
    //*************方法
    //无返回值无形参
    public void eat() {
        System.out.println("客户吃饭");
    }

    //无返回值有形参
    public void sleep(int hour) {
        System.out.println("休息了" + hour + "个小时");
    }

    //有返回值无形参
    public String getName() {
        return name; //类的方法可以调用类的属性
    }

    //有返回值有形参
    public String getNation(String nation) {
        String info = "我的国籍是" + nation;
        return info;
    }
}
1.1 权限修饰符
  • Java规定的4种权限修饰符:public、private、缺省(不写)、protected
1.2 返回值类型
  • 有返回值 vs 没有返回值
  1. 如果方法有返回值,则必须在方法声明时指定返回值的类型。同时,方法中需要使用return关键字返回指定类型的变量或常量:“return 变量或常量;”
  2. 返回值可以是任意数据类型的,可以是数组也可以是对象
class Customer {
	//这种情况会报错,因为只有当 age > 18 时才有返回值
    public String getName() {
        if (age > 18) {
        	return name;
        }
    }
    
    //这种情况不报错,因为任何情况下都有返回值
    public String getName() {
        if (age > 18) {
        	return name;
        } else {
        	return "Tom";
        }
    }
}
  1. 如果方法没有返回值,则声明时使用void来表示。通常,没有返回值的方法不需要使用return,如果使用 “return;” 则一旦遇到return关键字就结束方法
1.3 方法名
  • 方法名属于标识符,遵守标识符的规则和规范,见名知意
1.4 形参列表
  1. 方法可以声明0个、1个或多个形参
  2. 形参可以是任意数据类型的。可以作为数组的引用类型变量,存放堆空间中数组实体的地址值;也可以作为类的对象的引用类型变量,存放堆空间中对象实体的地址值
  3. 格式:数据类型1 形参1, 数据类型2 形参2, …

2. return关键字的使用

  1. 使用范围:方法体内
  2. 作用:①结束方法;②对于有返回值的方法,“return 变量或常量;” 返回指定类型的变量或常量
  3. 注意:return关键字后不可再声明执行语句

3. 方法的使用

  1. 方法体内可以调用当前类的属性、方法(调用时无需实例化对象,直接写属性名或者方法名;或者使用this修饰符来表示当前对象的属性或方法)
  2. 方法体内可以创建(new)当前类的对象
  3. 但在main方法内调用当前类的非静态(Non-static)方法时,需要实例化当前类的对象,再调用对象的方法。这是因为main方法是静态(static)的,在静态上下文中不能引用非静态方法
  4. 一般来说,方法体内一般调用的是其他方法,但也可以调用自己本身,这就是==递归==
  5. 方法内不可以定义方法

4. 例题

例1:Person类的创建

在这里插入图片描述

//Person类
public class Person {
    //属性
    String name;
    int age;
    int sex;

    //方法
    public void study() {
        System.out.println("studying");
    }

    public void showAge() {
        System.out.println(age);
    }

    public int addAge(int i) {
        age += i;
        return age;
    }
}

//测试类
public class Day08_PersonTest {
    public static void main(String[] args) {
        //*****实例化一个Person类的对象
        Person p1 = new Person();
        //给对象的属性赋值
        p1.name = "Tom";
        p1.age = 18;
        p1.sex = 1;
        //调用对象的方法
        p1.study();
        p1.showAge();
        int newAge = p1.addAge(2);
        System.out.println(p1.name + "的新年龄为:" + newAge); //20
        //此时p1指向的对象的age属性值也为20,其实就是把age属性的值赋给了一个新变量newAge
        System.out.println(p1.age);; //20

        //*****实例化第二个Person类的对象
        Person p2 = new Person();
        p2.showAge(); //0 初始化的值
        p2.addAge(10);
        p2.showAge(); //20
    }
}
例2:类Circle计算圆的面积
  • 利用面向对象的编程方法,设计类Circle计算圆的面积
//Circle类
public class Circle {
    double radius;

    public double computeArea() {
        double area = Math.PI * radius * radius;
        return area;
    }
}

//测试类
public class Day08_CircleTest {
    public static void main(String[] args) {
        Circle c1 = new Circle();
        c1.radius = 2;
        double c1Area = c1.computeArea();
        System.out.println(c1Area);
    }
}
例3:打印一个m*n的*型矩形
  • 声明一个Rectangle方法(m和n两个形参),在方法中打印一个m*n的*型矩形,并计算该矩形的面积, 将其作为方法返回值。在main方法中调用该方法,接收返回的面积值并打印
public class Day08_RectangleTest {
    public static void main(String[] args) {
        Day08_RectangleTest test = new Day08_RectangleTest();
        int area = test.Rectangle(10, 8);
        System.out.println(area);
        //或者不用定义新的变量,直接输出Rectangle方法的返回值
        //System.out.println(test.Rectangle(10, 8));
    }

    public int Rectangle(int m, int n) {
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                System.out.print("*" + " ");
            }
            System.out.println();
        }
        return m * n;
    }
}
例4:对象数组
  • 定义类Student,包含三个属性:学号number(int),年级state(int),成绩score(int)。 创建20个学生对象,学号为1到20,年级和成绩都由随机数确定
  • 问题一:打印出3年级(state值为3)的学生信息
  • 问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
  • ①生成随机数 Math.random(),返回值类型double; ②四舍五入取整 Math.round(double d),返回值类型long
public class Day08_StudentTest {
    public static void main(String[] args) {
        //声明一个Student类型的对象数组(类似于声明一个String类型的数组),长度为20
        Student[] stu = new Student[20];
        //实例化Student类的对象
        for (int i = 0; i < stu.length; i++) {
            //数组中的元素都是Student类的引用类型变量,这一步相当于给数组元素赋值(指向Student类的对象实体的地址值)
            stu[i] = new Student();

            //给每个Student类的对象的属性赋值
            stu[i].number = i + 1;
            //年级:[1, 6]的随机数
            stu[i].state = (int) Math.round(Math.random() * (6 - 1 + 1) + 1);
            //年级:[0, 100]的随机数
            stu[i].score = (int) Math.round(Math.random() * (100 - 0 + 1) + 0);
        }

        //遍历对象数组
        for (int i = 0; i < stu.length; i++) {
            //每个引用类型元素指向的Student类的对象实体的地址值
            System.out.println(stu[i]);
            //每个引用类型元素指向的Student类的对象实体的属性
            //System.out.println("学号:" + stu[i].number + ",年级:" + stu[i].state + ",成绩:" + stu[i].score);
            System.out.println(stu[i].info());
        }
        System.out.println("***************************");
        //问题一:打印出3年级(state值为3)的学生信息
        for (int i = 0; i < stu.length; i++) {
            if (stu[i].state == 3) {
                System.out.println(stu[i].info());
            }
        }
        System.out.println("***************************");
        //问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
        for (int i = 0; i < stu.length - 1; i++) {
            for (int j = 0; j < stu.length - 1 - i; j++) {
                //注意:stu[j]表示对象数组的每个元素,均为引用类型变量,它们的值都是地址值,不能比较大小
                //但他们指向的对象实体的属性score可以比较大小
                if (stu[j].score > stu[j + 1].score) {
//                    //方法一:交换指向的对象实体的属性
//                    int temp1 = stu[j].number;
//                    stu[j].number = stu[j + 1].number;
//                    stu[j + 1].number = temp1;
//                    int temp2 = stu[j].state;
//                    stu[j].state = stu[j + 1].state;
//                    stu[j + 1].state = temp2;
//                    int temp3 = stu[j].score;
//                    stu[j].score = stu[j + 1].score;
//                    stu[j + 1].score = temp3;

                    //方法二:交换指向的对象实体,即交换对象数组元素存放的地址值
                    //对象的引用类型变量的赋值,而并非对象的复制。将引用类型变量stu[j]指向的对象的地址值赋给了temp
                    Student temp = stu[j];
                    stu[j] = stu[j + 1];
                    stu[j + 1] = temp;
                }
            }
        }
        //遍历按成绩排序后的学生信息
        for (int i = 0; i < stu.length; i++) {
            System.out.println(stu[i].info());
        }
    }
}

class Student {
    int number; //学号
    int state; //年级
    int score; //成绩

    //显示学生信息的方法
    public String info() {
        return "学号:" + number + ",年级:" + state + ",成绩:" + score;
    }
}
  • 改进:将操作数组的方法封装到方法中
public class Day08_StudentTest {
    public static void main(String[] args) {
        //声明一个Student类型的对象数组(类似于声明一个String类型的数组),长度为20
        Student[] stu = new Student[20];
        //实例化Student类的对象
        for (int i = 0; i < stu.length; i++) {
            //数组中的元素都是Student类的引用类型变量,这一步相当于给数组元素赋值(指向Student类的对象实体的地址值)
            stu[i] = new Student();

            //给每个Student类的对象的属性赋值
            stu[i].number = i + 1;
            //年级:[1, 6]的随机数
            stu[i].state = (int) Math.round(Math.random() * (6 - 1 + 1) + 1);
            //年级:[0, 100]的随机数
            stu[i].score = (int) Math.round(Math.random() * (100 - 0 + 1) + 0);
        }

        //实例化一个类的对象,调用类中的方法
        Day08_StudentTest test = new Day08_StudentTest();
        //遍历对象数组
        test.print(stu);
        System.out.println("***************************");
        //问题一:打印出3年级(state值为3)的学生信息
        test.searchState(stu, 3);
        System.out.println("***************************");
        //问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
        test.sortScore(stu);
        //遍历按成绩排序后的学生信息
        test.print(stu);
    }

    //遍历Student[]数组的方法
    public void print(Student[] stu) {
        for (int i = 0; i < stu.length; i++) {
            System.out.println(stu[i].info());
        }
    }

    //查找指定年级的学生信息
    public void searchState(Student[] stu, int state) {
        for (int i = 0; i < stu.length; i++) {
            if (stu[i].state == state) {
                System.out.println(stu[i].info());
            }
        }
    }

    //使用冒泡排序按学生成绩排序
    public void sortScore(Student[] stu) {
        for (int i = 0; i < stu.length - 1; i++) {
            for (int j = 0; j < stu.length - 1 - i; j++) {
                //注意:stu[j]表示对象数组的每个元素,均为引用类型变量,它们的值都是地址值,不能比较大小
                //但他们指向的对象实体的属性score可以比较大小
                if (stu[j].score > stu[j + 1].score) {
                    //对象的引用类型变量的赋值,而并非对象的复制。将引用类型变量stu[j]指向的对象的地址值赋给了temp
                    Student temp = stu[j];
                    stu[j] = stu[j + 1];
                    stu[j + 1] = temp;
                }
            }
        }
    }
}

class Student {
    int number; //学号
    int state; //年级
    int score; //成绩

    //显示学生信息的方法
    public String info() {
        return "学号:" + number + ",年级:" + state + ",成绩:" + score;
    }
}

例5:自定义数组的工具类
public class Day09_ArrayUtil {
    //遍历数组
    public void print(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i] + " ");
        }

    }

    //求数组元素的最大值
    public int getMax(int[] arr) {
        int maxValue = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] > maxValue) {
                maxValue = arr[i];
            }
        }
        return maxValue;
    }

    //求数组元素的最小值
    public int getMin(int[] arr) {
        int minValue = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] < minValue) {
                minValue = arr[i];
            }
        }
        return minValue;
    }

    //求数组元素的和
    public int getSum(int[] arr) {
        int sum = 0;
        for (int i = 0; i < arr.length; i++) {
            sum += arr[i];
        }
        return sum;
    }

    //求数组元素的平均值
    public int getAvg(int[] arr) {
        //方法内调用当前类的方法时,不用实例化对象,直接写方法名
        return getSum(arr) / arr.length;
    }

    //反转数组
    public void reverse(int[] arr) {
        for (int i = 0; i < arr.length / 2; i++) {
            int temp = arr[i];
            arr[i] = arr[arr.length - 1 - i];
            arr[arr.length - 1 - i] = temp;
        }
    }

    //复制数组
    public int[] copy(int[] arr) {
        int[] copyArr = new int[arr.length];
        for (int i = 0; i < arr.length; i++) {
            copyArr[i] = arr[i];
        }
        return copyArr;
    }

    //数组排序(冒泡排序)
    public void sort(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }

    //查找数组中指定元素(二分法查找)
    public int getIndex(int[] arr, int dest) {
        //二分法适用的条件:排序后的数组
        sort(arr);
        //查找范围的首索引,初始为0
        int start = 0;
        //查找范围的末索引,初始为数组最后一个元素的索引
        int end = arr.length - 1;
        int index = -1;
        while (start <= end) {
            int mid = (start + end) / 2;
            if (dest == arr[mid]) {
                index = mid;
                break;
            } else if (dest < arr[mid]) {
                end = arr[mid] - 1;
            } else {
                start = arr[mid] + 1;
            }
        }
        return index;
    }

    //冒泡排序+二分法查找
    public int searchIndex(int[] arr, int dest) {

        //先对数组进行冒泡排序
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }

        //使用二分法查找
        int start = 0;
        int end = arr.length - 1;
        int index = -1;
        while (start <= end) {
            int mid = (start + end) / 2;
            if (dest == arr[mid]) {
                index = mid;
                break;
            } else if (dest < arr[mid]) {
                end = arr[mid] - 1;
            } else {
                start = arr[mid] + 1;
            }
        }
        return index;
    }
}

5. 方法的重载

  1. 重载的概念:在同一个类中,允许存在一个以上同名的方法,只要它们的参数个数或者参数类型不同即可。(两同一不同:同一类、同名的方法;不同的形参列表)
  2. 举例:Arrays类中重载的sort() / binarySearch()
  3. 注意:判断是否是方法重载,与方法的权限修饰符、返回值类型、形参变量名、方法体都没有关系。只需要看形参的个数、类型及类型的顺序是否不同
public class Day09_OverLoadTest {

    //方法的重载
    public void getSum(int i, int j) {
        System.out.println(i + j);
    }

    public void getSum(double i, double j) { //不同类型的形参
        System.out.println(i + j);
    }

    public void getSum(String s, int i) {

    }

    public void getSum(int i, String s) { //形参的类型交换次序也算重载

    }

    //不算方法的重载
    //public int getSum(int i, int j) {
    //    return 0;
    //}
    //
    //public int getSum(int m, int n) {
    //    return 0;
    //}
    //
    //private void getSum(int i, int j) {
    //}
}

6. 可变个数形参的方法

  1. 格式:数据类型 … 变量名
public void show(String ... strs) {}
  1. 当调用可变个数形参的方法时,传入的参数个数可以是0个、1个或者多个
  2. 可变个数形参的方法与同一类中方法名相同、形参列表不同的方法之间构成重载,可以共存
public void show(String ... strs) {}
public void show(String strs) {} //二者构成重载
  1. 可变个数形参的方法与同一类中方法名相同、形参为相同类型数组的方法之间不构成重载,不能共存
public void show(String ... strs) {}
public void show(String[] strs) {} //二者不构成重载,Java认为二者的形参列表是一致的
  1. 如果想要获取可变个数形参的每个参数,可以将其看成是一个数组
public void show(String ... strs) {
	for (int i = 0; i < strs.length; i++) { //可变个数形参也具有length属性
		System.out.print(strs[i] + " ")
	}
}
  1. 可变个数形参必须声明在形参列表的末尾,且最多只能在形参列表中声明一个可变个数形参
public void show(int i, String ... strs) {} //合法的
public void show(String ... strs, int i) {} //不合法的

7. 方法形参的值传递机制

7.1 变量的值传递
  1. 对于==基本数据类型的变量==,传递的是变量实际存储的数据值
int m = 10;
int n = m;
System.out.println(n); //10
n = 20;
System.out.println(m); //10
  1. 对于==引用数据类型的变量==,传递的是变量所指向的对象(或数组)实体在堆空间中的地址值
Order o1 = new Order();
Order o2 = o1; //将引用类型变量o1保存的对象地址值赋给o2,o1和o2指向同一个对象实体
o1.orderId = 1001;
System.out.println(o2.orderId); //1001
o2.orderId = 1002;
System.out.println(o1.orderId); //1002
7.2 方法形参的值传递
7.2.1 区分形参和实参
  1. 形参:在声明方法时,小括号(形参列表)里的参数
  2. 实参:在调用方法时,实际传递给形参的数据
7.2.2 形参的值传递机制
  1. 对于==基本数据类型的形参==,实参传递给形参的是实参实际存储的数据值
public class Day09_ValueTransferTest {
    public static void main(String[] args) {
        //实参m和n
        int m = 10;
        int n = 20;
        System.out.println("m = " + m + ", n = " + n); //m = 10, n = 20

        Day09_ValueTransferTest v = new Day09_ValueTransferTest();
        //此时只是swap方法内的形参进行了值的交换,main方法内的实参并没有交换值
        v.swap(m, n);
        System.out.println("m = " + m + ", n = " + n); //m = 10, n = 20
    }

    //交换两个变量值的方法
    public void swap(int m, int n) {
        //形参m和n
        int temp = m;
        m = n;
        n = temp;
    }
}

在这里插入图片描述

  • 注意,此时只是swap方法内的形参进行了值的交换,main方法内的实参并没有交换值
  1. 对于==引用数据类型的形参==,实参传递给形参的是实参所指向的对象(或数组)实体在堆空间中的地址值
public class Day09_ValueTransferTest {
    public static void main(String[] args) {
        Data data = new Data();
        data.m = 10;
        data.n = 20;
        System.out.println("m = " + data.m + ", n = " + data.n); //m = 10, n = 20

        //交换对象data的属性m和n的值
        Day09_ValueTransferTest v = new Day09_ValueTransferTest();
        v.swap(data);
        System.out.println("m = " + data.m + ", n = " + data.n); //m = 20, n = 10
    }

    //交换两个变量值的方法
    public void swap(Data data) {
        int temp = data.m;
        data.m = data.n;
        data.n = temp;
    }
}

class Data {
    int m;
    int n;
}

在这里插入图片描述

  • 注意,此时swap方法内的形参data(引用数据类型)和main方法内的实参(引用数据类型)data的值都等于同一个对象实体在堆空间中的地址值
7.3 例题
例1:不同数据类型的形参的值传递
public class TransferTest3 {
	public static void main(String args[]) {
		TransferTest3 test = new TransferTest3();
		test.first();
	}
    
	public void first() {
		int i = 5;
		Value v = new Value();
		v.i = 25;
		second(v, i);
		System.out.println(v.i + " " + i); //20 5
	}
    
	public void second(Value v, int i) {//将first方法内形参i的值作为实参传递给second方法内的形参i
		i = 0; // second方法内的形参i的值由开始的5变成了0
		v.i = 20; //此时second方法内的形参v和first方法内的形参v都指向同一个对象实体
		Value val = new Value();
        //将应用类型变量val指向的对象实体的地址值赋给了second方法内的形参v
        //此时second方法内的形参v和first方法内的形参v指向两个不同的对象实体
		v = val;
		System.out.println(v.i + " " + i); //15 0
    }
}

class Value {
	int i = 15;
}

在这里插入图片描述

例2:网红题
  • 要求:在method方法调用后,仅打印出 a = 100,b = 200, 请写出method方法的代码
public class Test {
	public static void main(String args[]) {
		int a = 10;
		int b = 10;
		method(a, b);
		System.out.println("a = " + a);
		System.out.println("b = " + b);
	}
    //代码编写处
}

错误做法:因为在调用method方法时,只是将main方法内的实参a和b的实际值传给了method方法内的形参a和b。在method方法内修改形参a和b的值,对main方法内的实参a和b没有任何影响!

public class Test {
	public static void main(String args[]) {
		int a = 10;
		int b = 10;
		method(a, b);
		System.out.println("a = " + a);
		System.out.println("b = " + b);
	}
    
    public void method(int a, int b) {
        a *= 10;
        b *= 20;
    }
}

此题考察的并不是方法形参的值传递,正确做法不用了解。

例3:将对象作为参数传递给方法
  1. 定义一个Circle类,包含一个double型的radius属性代表圆的半径,一个findArea()方法返回圆的面积
  2. 定义一个类PassObject,在类中定义一个方法printAreas(),该方法的定义如下:
    public void printAreas(Circle c, int time)
    在printAreas方法中打印输出1到time之间的每个整数半径值,以及对应的面积。例如,time为5,则输出半径1,2,3,4,5,以及对应的圆面积。
  3. 在main方法中调用printAreas()方法,调用完毕后输出当前半径值。
class Circle {
    double radius; //半径

    //计算圆的面积
    public double findArea() {
        return Math.PI * radius * radius;
    }
}

class PassObject {
    
    public static void main(String[] args) {
        PassObject test = new PassObject();
        Circle c = new Circle()
        test.printAreas(c, 5);
        System.out.println("now radius is:" + c.radius);
    }

    public void printAreas(Circle c, int time) {
        System.out.println("Radius\t\tArea");
        for (int i = 1; i <= time; i++) {
            c.radius = i;
            System.out.println(c.radius + "\t\t" + c.findArea());
        }
        c.radius += 1;
    }
}

8. 递归方法

  1. 递归的概念:在方法体内调用该方法本身
  2. 方法的递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制
  3. 递归一定要==向已知方向递归==,否则这种递归就变成了无穷递归,类似于死循环,可能会导致栈溢出
  4. 有规律的数列题可以考虑使用递归求解
8.1 递归的例题
例1:n以内自然数的和
public class Day09_RecursionTest {
    public int getSum(int n) {
        if (n == 1) {
            return 1;
        } else {
            return n + getSum(n - 1);
        }
    }
}
例2:n的阶乘
public class Day09_RecursionTest {
    public int getMultip(int n) {
        if (n == 1) {
            return 1;
        } else {
            return n * getMultip(n - 1);
        }
    }
}
例3:递归一定要向已知方向递归,否则就是无穷递归
  • 已知有一个数列,f(0) = 1,f(1) = 4,f(n + 2) = 2 * f(n + 1) + f(n),n > 0,求f(10)
public class Day09_RecursionTest {
    public int f(int n) {
        if (n == 0) {
            return 1;
        } else if (n == 1) {
            return 4;
        } else {
        	//千万不能写成 return f(n + 2) - 2 * f(n + 1); 不是向已知方向递归,会导致栈溢出
            return 2 * f(n - 1) + f(n - 2);
        }
    }
}
例4:斐波那契数列
  • 计算斐波那契数列的第n个值:1 1 2 3 5 8 13 21 34 55 ……;规律:第n个数等于前两个数之和
public class Day09_RecursionTest {
    public int fibonacci(int n) {
        if (n == 1) {
            return 1;
        } else if (n == 2) {
            return 1;
        } else {
            return f(n - 1) + f(n - 2);
        }
    }
}

四、面向对象的特征一:封装性(封装与隐藏)

1. 高内聚,低耦合

  • 高内聚:类的内部数据操作细节自己完成,不允许外部干涉
  • 低耦合:仅对外暴露少量的方法用于使用

2. 属性的封装性体现

将类的属性私有化(private),并提供公共的(public)方法来获取(getxxx)和设置(setxxx)该属性的值

  1. **封装:**正常情况下,通过 “对象.属性” 给对象的属性赋值仅受属性的数据类型和存储范围的限制,而没有其他限制条件。但在实际问题中,对象的属性值通常有明确的范围,此时就需要添加额外的限制条件。这些条件不能在声明属性时添加,但可以通过声明方法来添加,如下例中的 setLegs() 方法。
  2. **隐藏:**同时,我们需要避免用户再使用 “对象.属性” 的方式对属性赋值,因此需要将属性声明为 private 的
  • private:私有的,表示只能在类中使用,不能在子类及类的外部使用
public class Day10_AnimalTest {
    public static void main(String[] args) {
        Animal a = new Animal();
        // a.legs = 4; //'legs' has private access in 'test.Animal'
        a.setLegs(6);
    }
}

class Animal{
    //对legs属性的封装和隐藏
    //private表示只能在类中使用,不能在子类及类的外部使用
    private int legs;
    //设置legs属性值的方法
    public void setLegs(int l) {
        if (l >= 0 && l % 2 == 0) {
            legs = l;
        } else {
            legs = 0;
            //或者抛出一个异常
        }
    }
    
    //获取legs属性值的方法
    public int getLegs() {
    	return legs;
    }
}

3. 权限修饰符

3.1 Java的4种权限修饰符
  • 按权限从小到大排列:private、default(缺省)、protected、public
  • 权限修饰符可以用来修饰类及类的成员,体现类及类的成员在被调用时的可见性的大小
3.2 对类的权限修饰:只能用public和default(缺省)
  • 对于类的权限修饰只能用public和default(缺省)
  • public类可以在任意地方被访问
  • default(缺省)类只能被同一个包(package)内的类访问
3.3 对类的成员的权限修饰:4种都可以
  • 置于类的成员(属性、方法、构造器、内部类)的定义前,用来限制对象对该类成员的访问权限
  • 代码块不能使用权限修饰符

在这里插入图片描述

五、类的成员之三:构造器

1. 构造器的作用

  1. 创建类的对象:类名 对象名 = new 构造器;
  2. 给对象进行初始化: 声明构造器时还可以给对象的属性赋初始化值

2. 声明构造器的格式

  • 权限修饰符 类名(形参列表){}
class Person {
	//属性
	String name;
	int age;
	
	//构造器1
	public Person(String n) {
		name = n; //通过这种方式,一旦new一个新对象,其name属性就初始化为形参n的值
	}
	
	//构造器2: 构造器的重载
	public Person(String n, int a) {
		name = n;
		age = a;
	}
	
	//方法
	public void eat() {
		System.out.println("人吃饭");
	}
}

3. 说明

  1. 构造器与类同名,但是后面多了一对括号
  2. 一个类中,至少会存在一个构造器。如果没有显式的定义构造器,系统会默认提供一个无参的构造器,且该默认无参构造器与类的权限保持一致;一旦显式的定义了构造器,系统就不再提供默认的无参构造器
  3. 声明构造器的格式与声明方法的格式比较相似,但构造器的声明不包含返回值类型,不能有return语句返回值,不能被static、final、synchronized、abstract、native修饰
  4. 不要把构造器看成一种特殊的方法,构造器只在创建对象时使用
  5. **构造器的重载:**在同一个类中可以声明多个构造器

4. 构造器例题

编写两个类,TriAngle和TriAngleTest,其中TriAngle类中声明私有的底边长base和高height,同时声明公共方法访问私有变量。此外,提供类必要的构造器。另一个类中使用这些公共方法,计算三角形的面积。

public class Day10_TriAngleTest {
    public static void main(String[] args) {
        TriAngle test = new TriAngle(1.0, 1.0);
        System.out.println(test.getBase()); //1.0
        System.out.println(test.getHeight()); //1.0
        test.setBase(2.0);
        test.setHeight(2.0);
        System.out.println(test.getBase()); //2.0
        System.out.println(test.getHeight()); //2.0
        System.out.println(test.getArea()); //2.0
    }
}


class TriAngle {
    //声明私有的属性
    private double base;
    private double height;

    //构造器1:空参
    public TriAngle() {
    }

    //构造器2:
    public TriAngle(double b, double h) {
        base = b;
        height = h;
    }

    //声明公共方法访问私有属性
    public void setBase(double b) {
        if (b > 0) {
            base = b;
        } else {
            System.out.println("请输入大于0的底边长");
        }
    }

    public double getBase() {
        return base;
    }

    public void setHeight(double h) {
        if (h > 0) {
            height = h;
        } else {
            System.out.println("请输入大于0的高");
        }
    }

    public double getHeight() {
        return height;
    }

    //计算三角形面积的方法
    public double getArea() {
        return 0.5 * base * height;
    }
}

扩展知识1:JavaBean

  • 定义:JavaBean是一种Java语言写成的可重用组件
  • JavaBean是指符合如下标准的Java类:
  1. 类是公共的
  2. 有一个无参的公共的构造器
  3. 有属性,且有对应的get、set方法
public class Customer {
	private int id;
	private String name;
	
	//空参构造器
	public Customer() {
	
	}
	
	public void setId(int i) {
		id = i;
	}
	
	public int getId() {
		return id;
	}
	
	public void setName(String n) {
		name = n;
	}
	
	public String getName() {
		return name;
	}
}

扩展知识2:UML类图

在这里插入图片描述

六、关键字:this

1. 问题的由来

  1. 在对类的属性进行封装时,我们希望 “setxxx” 方法中的形参"见名知义",故使用this关键字来修饰当前类的属性,与方法中的同名形参进行区分
  2. 在设计类的构造器时,如果构造器中条件的声明过于冗余,我们希望可以在构造器中调用当前类的其他构造器

2. this关键字的使用

  1. 用来修饰属性和方法
  2. 用来调用构造器
2.1 this修饰属性和方法:表示当前对象
  1. this修饰属性和方法:this理解为当前对象(在方法中)当前正在创建的对象(在构造器中)!!!!!
  • p1.setAge(1):p1指向的对象调用setAge()方法,则setAge()中的this.age相当于p1.age
  • Boy类中的marry方法的形参是Girl类型的,在Girl类中调用时,可以直接传入一个this表示当前Girl类的对象(调用该方法的对象)
class Boy {
    private String name;
    
    public String getName() {
        return name;
    }

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

    public void marry(Girl girl) {
        System.out.println("我想娶:" + girl.getName());
    }

class Girl {
    private String name;

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

    public String getName() {
        return name;
    }

    public void marry(Boy boy) {
        System.out.println("我想嫁给:" + boy.getName());
        //this表示当前对象(调用该方法的对象)
        boy.marry(this);
    }
    
    /**
     * @Description 比较两个对象的大小:当前对象(调用该方法的对象,即this) VS 形参对象(传递给形参的地址值指向的对象,即girl)
     * @param girl
     * @return 正数:当前对象大;负数:当前对象小;0:当前对象和形参对象相等
     */
    public int compare(Girl girl) {
        //this表示当前调用该方法的Girl类型对象,而girl表示传递给形参的地址值指向的对象
        if (this.age > girl.age) {
            return 1;
        } else if (this.age < girl.age) {
            return -1;
        } else {
            return 0;
        }
    }
}
  1. 在类的==方法==中,我们可以使用 “this.属性” 或 “this.方法” 来调用当前对象的属性和方法。但通常情况下,我们都选择省略 this;如果方法的形参和当前类的属性重名时,则必须要用this关键字显式的修饰该属性(成员变量),表明该变量是属性,不是形参。
  2. 在类的==构造器==中,我们可以使用 “this.属性” 或 “this.方法” 来调用当前类当前正在创建的对象的属性和方法。但通常情况下,我们都选择省略 this;如果构造器的形参和当前类的属性重名时,则必须要用this关键字显式的修饰该属性(成员变量),表明该变量是属性,不是形参。
2.2 this调用构造器:this(形参列表)
  1. 在类的构造器中,可以显式的使用 “this(形参列表)” 的方式,调用当前类中指定(通过形参列表的形式来指定)的其他构造器
  2. 构造器中不能通过 “this(形参列表)” 的方式来调用自己,只能调用当前类的其他构造器
  3. 如果一个类中有n个构造器,则最多只能有n-1个构造器调用了其他构造器
  4. 规定:如果要在构造器中调用当前类的其他构造器,则必须要将 “this(形参列表)” 声明在首行;一个构造器内部最多只能声明一个 “this(形参列表)” ,即最多只能调用一个其他构造器
public class Day10_ThisTest {
    public static void main(String[] args) {
        Person1 p1 = new Person1();
        p1.setAge(1); //p1指向的对象调用setAge()方法,则setAge()中的this.age相当于p1.age
        System.out.println(p1.getAge());
    }
}

class Person1 {
    private String name;
    private int age;

    //********************** this在构造器中的使用
    public Person1() {

    }
    
    public Person1(String name) {
		this.name = name; //若形参和属性重名,this不能省略
	}

    public Person1(String name, int age) {
        this(name); //在构造器中调用当前类中指定的其他构造器,放在首行
        this.age = age; //若形参和属性重名,this不能省略
    }
	
	//********************** this修饰属性和方法
    public void setName(String name) {
        this.name = name; //若形参和属性重名,this不能省略
    }

    public String getName() {
        return this.name; //可以省略
    }

    public void setAge(int age) {
        this.age = age; //若形参和属性重名,this不能省略
    }

    public int getAge() {
        return this.age; //可以省略
    }

    public void eat() {
        System.out.println("吃饭");
        this.drink(); //可以省略
    }

    public void drink() {
        System.out.println("喝水");
    }
}

3. this关键字例题

3.1 例1:this关键字的综合应用+UML类图

在这里插入图片描述

class Boy {
    private String name;
    private int age;

    public Boy() {
    }

    public Boy(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 void marry(Girl girl) {
        System.out.println("我想娶:" + girl.getName());
    }

    public void shout() {
        if (this.age >= 22) {
            System.out.println("你到法定结婚年龄了");
        } else {
            System.out.println("你还没到法定结婚年龄");
        }
    }
}

class Girl {
    private String name;
    private int age;

    public Girl() {
    }

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

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

    public String getName() {
        return name;
    }

    public void marry(Boy boy) {
        System.out.println("我想嫁给:" + boy.getName());
        //this表示当前对象(调用该方法的对象)
        boy.marry(this);
    }

    /**
     * @Description 比较两个对象的大小:当前对象(调用该方法的对象,即this) VS 形参对象(传递给形参的地址值指向的对象,即girl)
     * @param girl
     * @return 正数:当前对象大;负数:当前对象小;0:当前对象和形参对象相等
     */
    public int compare(Girl girl) {
        //this表示当前调用该方法的Girl类型对象,而girl表示传递给形参的地址值指向的对象
        if (this.age > girl.age) {
            return 1;
        } else if (this.age < girl.age) {
            return -1;
        } else {
            return 0;
        }
    }
}

实验:Account_Customer_Bank

题目要求

  1. 按照如下的 UML 类图,创建相应的类,提供必要的结构。在提款方法 withdraw()中,需要判断用户余额是否能够满足提款数额的要求,如果不能, 应给出提示。deposit()方法表示存款。
    在这里插入图片描述

  2. 按照如下的 UML 类图,创建相应的类,提供必要的结构
    在这里插入图片描述

  3. 按照如下的 UML 类图,创建相应的类,提供必要的结构

  • addCustomer 方法必须依照参数(姓,名)构造一个新的 Customer 对象,然后把它放到 customers 数组中。还必须把 numberOfCustomer 属性的值加 1。
  • getNumOfCustomers 方法返回 numberofCustomers 属性值。
  • getCustomer 方法返回与给出的 index 参数相关的客户。
    在这里插入图片描述
  1. 创建 BankTest 类,进行测试

思路

  1. 在银行对象创建后,如果想添加客户对象及其对应的账户对象,需要首先调用银行对象的 addCustomer() 方法创建一个客户对象,addCustomer() 会将客户对象的地址值传给银行对象的customers属性(对象数组)的元素,此时可以通过调用银行对象的 getCustomer() 方法获取对象数组指定索引的客户对象,并调用客户对象的setAccount() 方法,实例化一个新的账户对象。注意,虽然我们在调用 setAccount() 方法时给形参传了一个匿名对象的地址值,但在该方法内部,该地址值会直接传递给客户对象的 account属性,相当于将银行、客户和账户三者链接了起来
  2. 此时如果想对账户进行操作(存钱或取钱),首先应调用银行对象的 getCustomer() 方法获取对象数组指定索引的客户对象,然后调用客户对象的getAccount() 方法获取账户对象,然后再对账户对象进行操作,如==bank.getCustomer(0).getAccount().withdraw(500);==
    银行 => 客户 => 账户:连续操作
  3. 在对数组进行赋值之前,一定要对先对其进行初始化,确定其数组长度(即在堆空间中开辟一块新的数组空间),否则会报空指针的错误
public class Day10_BankTest {
    public static void main(String[] args) {
        //创建一个银行
        Bank bank = new Bank();
        //银行添加一个客户
        bank.addCustomer("Jane", "Smith");

        //银行 => 客户 => 账户:连续操作
        //通过银行获取客户对象,然后在通过客户对象调用setAccount方法链接一个新的账户对象
        bank.getCustomer(0).setAccount(new Account1(2000));
        //通过银行获取客户对象,然后在通过客户对象调用getAccount()方法获取账户对象,然后再调用账户对象的withdraw()方法
        bank.getCustomer(0).getAccount().withdraw(500);
        double balance = bank.getCustomer(0).getAccount().getBalance();
        System.out.println(balance);
    }
}


class Account1 {
    //属性
    private double balance;

    //构造器
    public Account1(double init_balance) {
        this.balance = init_balance;
    }

    //获取balance值
    public double getBalance() {
        return balance;
    }

    //取钱
    public void withdraw(double amt) {
        if (balance < amt) {
            System.out.println("余额不足,取款失败");
        } else {
            balance -= amt;
            System.out.println("成功取出:" + amt);
        }
    }

    //存钱
    public void deposit(double amt) {
        if (amt > 0) {
            balance += amt;
            System.out.println("成功存入:" + amt);
        }
    }
}

class Customer2 {
    //属性
    private String firstName;
    private String lastName;
    private Account1 account; //account属性是自定义类Account的引用类型变量

    //构造器
    public Customer2(String f, String i) {
        this.firstName = f;
        this.lastName = i;
    }

    //方法
    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public Account1 getAccount() {
        return account;
    }

    public void setAccount(Account1 account) {
        this.account = account; //将形参的地址值赋给当前对象的account属性
    }
}

class Bank {
    //属性
    private Customer2[] customers; //对象数组
    private int numberOfCustomer;

    //构造器
    public Bank() {
        customers = new Customer2[10]; //对象数组初始化,否则会报空指针错误
    }

    //添加客户
    public void addCustomer(String f, String l) {
        Customer2 customer = new Customer2(f, l);
        //将new出来的客户对象的地址值赋给数组元素,使数组元素指向客户对象,这一步一定要确保对象数组已经初始化过了,否则会报空指针错误
        customers[numberOfCustomer] = customer;
        numberOfCustomer++;
        //customers[numberOfCustomer++] = customer;
    }

    //获取客户的个数
    public int getNumberOfCustomer() {
        return  numberOfCustomer;
    }

    //获取指定索引的客户对象
    public Customer2 getCustomer(int index) {
        if (index >= 0 && index < numberOfCustomer) {
            return customers[index];
        } else {
            return null;
        }
    }
}

七、关键字:package/import

1. package关键字的使用

  1. 为了更好地对项目中的接口、类进行管理,提出了package(包)的概念
  2. 使用package声明接口、类所属的包,声明在源文件的首行
  3. 包名属于标识符,遵循标识符的命名规则和规范
  4. 包名中每 “.” 点一次,就代表一层文件目录
  5. 同一个包下,不能声明同名的接口、类;不同的包下,可以声明同名的接口、类

2. MVC设计模式

在这里插入图片描述

3. import关键字的使用

  1. 在源文件中显式的使用import结构导入指定包下的类、接口
  2. import声明的位置在包的声明和类的声明之间
  3. 如果需要导入多个类、接口,依次写出即可
  4. 使用 “xxx.*” 的方式,表示导入xxx包下的所有类、接口
import java.util.* //表示调入java.util下的所有类和接口
  1. 如果使用的类、接口时在java.lang包下定义的,则无需导包
  2. 如果使用的类、接口是当前包下定义的,则无需导包
  3. 如果在源文件中使用了不同包下的同名的类,则至少有一个类需要使用全类名的方式显式
  4. 使用 “xxx.*” 的方式表明可以调用xxx包下的所有结构,但如果使用xxx的子包下的结构,仍需要显式的导入
  5. import static:导入指定类或接口中的静态结构:属性或方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值