第七章 面向对象编程(基础) 下


在这里插入图片描述

第七章 面向对象编程(基础) 上

本章知识点

  1. 随机数函数 new Random().nextInt()

1.方法重载overLoad

基本介绍

●java允许同一个类中, 多个同名方法的存在, 但要求 形参列表不一致! 比如: System.out.println();

在这里插入图片描述


●重载的好处
1)减轻了起名的麻烦
2)减轻了记名的麻烦

public class OverLoad01 {

	//编写一个main方法
	public static void main(String[] args) {
		System.out.println(100);
		System.out.println("hello, world");
		System.out.println('h');
		System.out.println(1.1);
		System.out.println(true);
	}	
}

快速入门

OverLoad01.java
案例: 类: MyCalculator 方法: calculate
calculate(int n1, int n2) //两个整数的和
calculate(int n1, double n2) //一个整数, 一个double的和
calculate(double n2, int n1) //一个double, 一个int的和
calculate(int n1, int n2, int n3) //三个int的和

public class OverLoad01 {

	//编写一个main方法
	public static void main(String[] args) {

		MyCalculator my = new MyCalculator();
		System.out.println(my.calculate(11, 22));//调用的是 calculate(int n1, int n2)
		System.out.println(my.calculate(1.1, 2));//调用的是 calculate(double n1, int n2)
		System.out.println(my.calculate(1, 2.2));//调用的是 calculate(int n1, double n2)
		System.out.println(my.calculate(1.1, 2.2));//会报错: 参数不匹配; 从double转换到int可能会有损失
	}
}

class MyCalculator {
	//下面的四个 calculate方法构成了重载

	//返回两个整数的和
	public int calculate(int n1, int n2) {
		System.out.println("calculate(int n1, int n2) 并调用...");
		return n1 + n2;
	}
	//返回一个整数, 一个double的和
	public double calculate(int n1, double n2) {
		System.out.println("calculate(int n1, double n2) 并调用...");
		return n1 + n2;
	}
	//返回一个double, 一个整数的和
	public double calculate(double n1, int n2) {
		System.out.println("calculate(double n1, int n2) 并调用...");
		return n1 + n2;
	}
	//返回三个整数的和
	public int calculate(int n1, int n2, int n3) {
		System.out.println("calculate(int n1, int n2, int n3) 并调用...");
		return n1 + n2 + n3;
	}
}

注意事项和细节

1)方法名: 必须相同
2)形参列表: 必须不同 (形参类型个数顺序, 至少有一个不同, 参数名无要求)

//下面的方法是否构成重载? => 没有构成重载, 而是方法的重复定义
public int calculate(int a1, int a2) {
	return a1 + a2;
}

public int calculate(int n1, int n2) {
	return n1 + n2;
}

在这里插入图片描述

3)返回类型: 无要求

//没有构成方法重载, 仍然是错误的, 因为是方法的重复定义
public void calculate(int n1, int n2) {
	int res = n1 + n2;
}

public int calculate(int n1, int n2) {
	return n1 + n2;
}

在这里插入图片描述

课堂练习

1.判断题:
void show(int a, char b, double c){}构成重载的有: bcde
a) void show(int x, char y, double z){} //不是
b) int show(int a, double c, char b){} //是
c) void show(int a, double c, char b){} //是

d) boolean show(int c, char b){} //是
e) void show(double c){} //是
f) double show(int x, char y, double z){} //不是
g) void shows(){} //不是

2.编写程序, 类Methods中定义三个重载方法并调用. 方法名为m. 三个方法分别接收一个int参数, 两个int参数, 一个字符串参数. 分别执行平方运算并输出结果, 相乘输出结果, 输出字符串信息. 在主类的main()方法中分别用参数区别调用三个方法.OverLoadExercise.java

public class OverLoadExercise {

	//编写一个main方法
	public static void main(String[] args) {
        Methods method = new Methods();
        method.m(10);//100
        method.m(10, 15);//150
        method.m("赵志伟");//字符串信息
	}
}

/*
编写程序, 类Methods中定义三个重载方法并调用, 方法名为m. 
三个方法分别接收一个int参数, 两个int参数, 一个字符串参数. 
分别执行平方运算并输出结果, 相乘输出结果, 输出字符串信息. 
在主类的main()方法中分别用参数区别调用三个方法.
 */
class Methods {

    //分析
    //1.方法名 m
    //2.形参列表 (int)
    //3.返回值 void
    public void m(int n) {
        System.out.println("平方=" + (n * n));
    }

    //1.方法名 m
    //2.形参列表 (int, int)
    //3.返回值 void
    public void m(int n1, int n2) {
        System.out.println("相乘=" + (n1 * n2));
    }

    //1.方法名 m
    //2.形参列表 (String)
    //3.返回值 void
    public void m(String str) {
        System.out.println("传入的字符串=" + str);
    }
}

3.在Methods类, 定义三个重载方法max(). 第一个方法, 返回两个int值中的最大值; 第二个方法, 返回两个double值中的最大值; 第三个方法, 返回三个double值中的最大值. 并分别调用三个方法.

public class OverLoadExercise {

	//编写一个main方法
	public static void main(String[] args) {

		Methods method = new Methods();

		//测试
        System.out.println(method.max(10, 24));//24 max(int n1, int n2)
        System.out.println(method.max(10.0, 24));//24.0 max(double d1, double d2)
        System.out.println(method.max(10.0, 24.0, 30.0));//30.0 max(double d1, double d2, double d3)
        System.out.println(method.max(10.0, 24.0, 30));//30.0 max(double d1, double d2, int d3)
	}
}

/*
在Methods类, 定义三个重载方法max(). 
第一个方法, 返回两个int值中的最大值; 
第二个方法, 返回两个double值中的最大值; 
第三个方法, 返回三个double值中的最大值. 
并分别调用三个方法.
 */
class Methods {

    //分析
    //1.方法名 max
    //2.形参列表 (int, int)
    //3.返回值 int    
    public int max(int n1, int n2) {
        return n1 >= n2 ? n1 : n2;   
    }

	//分析
	//1.方法名 max
	//2.形参 (double, double)
	//3.double
	public double max(double n1, double n2) {
		return n1 > n2 ? n1 : n2;
	}

	//分析
	//1.方法名
	//2.形参 (double, double, double)
	//3.double
	public double max(double n1, double n2, double n3) {
		System.out.println("max(double n1, double n2, double n3) 被调用...");
		//求出n1 和 n2的最大值
		double max1 = max(n1, n2);
		return max1 > n3 ? max1 : n3;
	}

	public double max(double n1, double n2, int n3) {
		System.out.println("max(double n1, double n2, int n3) 被调用...");
		//求出n1 和 n2的最大值
		double max1 = max(n1, n2);
		return max1 > n3 ? max1 : n3;
	}
}

这两个方法构成重载.
在这里插入图片描述

2.可变参数

●基本概念
java允许将同一个类中 多个同名同功能但参数个数不同的方法, 封装成一个方法. 就可以通过可变参数实现

●基本语法
访问修饰符 返回类型 方法名 (数据类型… 形参名) {}

●案例快速入门 VarParameter01.java
看一个案例. 类 ZzwMethod, 方法 sum, 可以计算2个数的和, 3个数的和, 4个数的和, 5…

public class VarParameter01 {

	//编写一个main方法
	public static void main(String[] args) {
        ZzwMethod m = new ZzwMethod();
        System.out.println(m.sum(1, 5, 100));//106
        System.out.println(m.sum(1, 19));//20
	}
}

class ZzwMethod {

    //看一个案例. 类 ZzwMethod, 方法 sum
    //, 可以计算2个数的和, 3个数的和, 4个数的和, 5...
    /*public int sum(int n1, int n2) {//2个数的和
        return n1 + n2;
    }

    public int sum(int n1, int n2, int n3) {//3个数的和
        return n1 + n2 + n3;
    }

    public int sum(int n1, int n2, int n3, int n4) {//4个数的和
        return n1 + n2 + n3 + n4;
    }*/

    //...

    //上面三个方法名称相同, 功能相同, 参数个数不同-> 使用可变参数优化
    //解读
    //1. int... 表示接收的是可变参数, 类型是int, 即可以接收多个int(0-多)
    //2. 使用可变参数时, 可以当作数组来使用, 即 nums 可以当作数组
    //3. 遍历 nums 求和即可
    public int sum(int... nums) {
        // System.out.println("接收的参数个数=" + nums.length);
        int res = 0;
        for(int i = 0; i < nums.length; i++) {
            res += nums[i];
        }
        return res;
    }
} 

●注意事项和细节 VarParameterDetail.java
1)可变参数的实参可以为0个或任意多个.
2)可变参数的实参可以为数组.
3)可以参数的本质就是数组.

4)可变参数可以和普通类型的参数一起放在形参列表, 但必须保证可变参数在最后.
5)一个形参列表中只能出现一个可变参数.

public class VarParameterDetail {

	//编写一个main方法
	public static void main(String[] args) {
        //细节: 可变参数的实参可以为数组
        int[] arr = {1, 2, 3};
        T t1 = new T();
        t1.f1(arr);
	}
}

class T {

    public void f1(int... nums) {
        System.out.println("长度=" + nums.length);
    }

    //细节: 可变参数可以和普通类型的参数一起放在形参列表, 但必须保证可变参数在最后
    public void f2(String str, double... nums) {

    }
    //细节: 一个形参列表中只能出现一个可变参数
    //下面的写法是错的.
    public void f3(int... str, double... nums) {

    }
}

课堂练习

VarParameterExercise.java
有三个方法, 分别实现返回姓名和两门课成绩(总分), 返回姓名和三门课成绩(总分), 返回姓名和五门课成绩(总分). 封装成一个可变参数的方法.

类名 ZzwMethod 方法名 showScore

public class VarParameterExercise {

	//编写一个main方法
	public static void main(String[] args) {
        ZzwMethod m = new ZzwMethod();
        System.out.println(m.showScore("赵志伟", 140, 80));
        System.out.println(m.showScore("tom", 70, 80, 90));
	}
}

/*
有三个方法, 分别实现返回姓名和两门课成绩(总分), 
返回姓名和三门课成绩(总分), 返回姓名和五门课成绩(总分). 
封装成一个可变参数的方法.
 */
class ZzwMethod {

    //分析
    //1.方法名 showScore
    //2.形参列表 (String name, double... scores)
    //3.返回值 String
    public String showScore(String name, double... scores) {
        double totalScore = 0;
        for(int i = 0; i < scores.length; i++) {
            totalScore += scores[i];
        }
        return "姓名 " + name + "\t" + scores.length + "门课总分 " + totalScore;
    }
}

3.Java作用域

●基本使用 VarScope.java
面向对象中, 变量作用域是 非常重要的知识点. 相对来说不是特别好理解.

1.在java编程中, 主要的变量就是属性(成员变量) 和局部变量
2.我们说的局部变量一般是指在成员方法中定义的变量.
3.java中作用域的分类
     ●全局变量: 也就是属性, 作用域为整个类体.
     ●局部变量: 也就是除了属性之外的其它变量, 作用域为定义它的代码块中!

4.全局变量(属性) 可以不赋值, 直接使用, 因为有默认值; 局部变量必须赋值后, 才能使用, 因为没有默认值.

public class VarScope {

	//编写一个main方法
	public static void main(String[] args) {
        
	}
}

class Cat {

    //全局变量: 也就是属性, 作用域为整个类体.
    //属性在定义时可以直接赋值
    int age = 10;//指定的值是 10

    //全局变量(属性) 可以不赋值, 直接使用, 因为有默认值; 
    double weight; //默认值是0.0

    public void hi() {
        //局部变量必须赋值后, 才能使用, 因为没有默认值.
        int num = 1;
        String address = "橘猫";
        System.out.println("num=" + num);
        System.out.println("address=" + address);
        System.out.println("weight=" + weight);
    }

    public void cry() {
        //1.局部变量一般是指在成员方法中定义的变量
        //2.n 和 name 就是局部变量
        //3.n 和 name 的作用域在cry方法中
        int n = 10;
        String name = "jack";
        System.out.println("在cry()中使用属性 age=" + age);
    }

    public void eat() {
        System.out.println("在eat()中使用属性 age=" + age);
        // System.out.println("在eat()中使用 cry()的变量 name=" + name);//错误
    }
}

注意事项和细节

1.属性和局部变量可以重名, 访问时遵循就近原则. VarScopeDetail.java
2.在同一个作用域中, 比如在同一个成员方法中, 两个局部变量, 不能重名.

3.属性生命周期较长, 伴随着对象的创建而创建, 伴随着对象的销毁而销毁. 局部变量, 生命周期较短, 伴随着它的代码块的执行而创建, 伴随着代码块的结束而销毁. 即在一次方法的调用过程中生效.

4.作用域范围不同
全局变量/属性: 可以被本类使用, 或其它类使用 (通过对象调用)
局部变量: 只能在本类对应的方法中使用

5.修饰符不同
全部变量/属性可以加修饰符.
局部变量不可以加修饰符, 否则会报错
在这里插入图片描述在这里插入图片描述

代码实现

public class VarScopeDetail {

	//编写一个main方法
	public static void main(String[] args) {
        Person p1 = new Person();
        /*
        属性生命周期较长, 伴随着对象的创建而创建, 伴随着对象的销毁而销毁. 
        局部变量, 生命周期较短, 伴随着它的代码块的执行而创建, 伴随着代码块的结束而销毁. 
        即在一次方法的调用过程中生效.
         */
        //当执行say方法时,say方法的局部变量比如name, 会创建, 当say执行完毕后
        //name局部变量就销毁, 但是属性(全局变量)仍然可以使用
        p1.say();

        T t1 = new T(); 
        t1.test();//第1种跨类访问对象属性的方式
        t1.test2(p1);//第2种跨类访问对象属性的方式
	}
}

class T {
    //全局变量/属性: 可以被本类使用, 或其它类使用 (通过对象调用)
    public void test() {
        Person p1 = new Person();
        System.out.println(p1.name);//jack
    }

    public void test2(Person p) {
        System.out.println(p.name);//jack
    }
}

class Person {

    //细节: 属性可以加修饰符(public protected private..)
    //      局部变量不能加修饰符
    public int age = 20;

    String name = "jack";

    public void say() {
        //细节: 属性和局部变量可以重名, 访问时遵循就近原则.
        String name = "king";
        System.out.println("say() name=" + name);
    }
}

4.构造方法/构造器

●看一个需求
我们来看一个需求: 前面我们在创建人类的对象时, 是先把一个对象创建好后, 再给它的年龄和姓名属性赋值. 如果现在这么要求: 在创建人类对象时, 就直接指定这个对象的年龄和姓名, 该怎么做? 这时就可以使用构造器.

●基本语法
[修饰符] 方法名(形参列表) { 方法体 }

●说明:
1)构造器的修饰符可以默认, 也可以是 public protected private
2)构造器没有返回值
3)方法名 和类名字必须一样
4)参数列表 和 成员方法一样的规则
5)构造器的调用, 由系统完成

●基本介绍
构造方法又叫构造器(constructor), 是类的一种特殊的方法, 它的主要作用是完成对新对象的初始化. 它有几个特点:
1.方法名和类名相同
2.没有返回值
3.在创建对象时, 系统会自动地调用该类的构造器完成对象的初始化.

快速入门

用构造方法完成: 在创建人类的对象时, 就直接指定这个对象的年龄和姓名 Constructor01.java

public class Constructor01 {

	//编写一个main方法
	public static void main(String[] args) {
        //当我们new 一样对象时, 直接通过构造器指定名字和年龄
        Person p1 = new Person("smith", 80);
        System.out.println("p1的信息如下");
        System.out.println("p1对象name=" + p1.name);
        System.out.println("p1对象age=" + p1.age);
	}
}

//用构造方法完成: 在创建人类的对象时, 就直接指定这个对象的年龄和姓名
class Person {
    String name;
    int age;
    //构造器
    //解读
    //1.构造器没有返回值, 也不能写void
    //2.构造器的名称和类Person一样
    //3.(String pName, int pAge) 是构造器形参列表, 规则和成员方法一样
    public Person(String pName, int pAge) {
        System.out.println("构造器被调用~~ 完成对象属性的初始化");
        name = pName;
        age = pAge;
    }
}

注意事项和细节

1.一个类可以定义多个不同的构造器, 即构造器重载 ConstructorDetail.java
比如: 我们可以再给Person类定义一个构造器, 用来创建对象的时候, 只指定人名, 不需要指定年龄.

2.构造器名和类名要相同
3.构造器没有返回值

4.构造器是完成对象的初始化, 并不是创建对象
5.在创建对象时, 系统自动地调用该类的构造方法

6.如果程序员没有定义构造器, 系统会自动地给类生成一个默认无参构造器 (也叫默认构造器). 比如 Dog() {}.
使用javap指令 反编译查看一下. javap使用文档
在这里插入图片描述

在这里插入图片描述
7.一旦定义了自己的构造器, 默认的构造器就被覆盖了, 就不能再使用默认的无参构造器, 除非显式地定义一下, 即: Dog() {} (这点很重要)

public class ConstructorDetail {

	//编写一个main方法
	public static void main(String[] args) {
        Person p1 = new Person("king", 40);//第一个构造器
        Person p2 = new Person("tom");//第二个构造器

        Dog dog1 = new Dog();//使用的是默认的无参构造器
	}
}

class Dog {
    //如果程序员没有定义构造器, 系统会自动地给类生成一个默认无参构造器 (也叫默认构造器). 
    /*
        默认构造器
        Dog() {
            
        }
     */
    //一旦定义了自己的构造器, 默认的构造器就被覆盖了, 就不能再使用默认的无参构造器, 
    //除非显式地定义一下, 即: Dog() {}
    public Dog(String dName) {

    }
    Dog() {//显示地定义一下 无参构造器

    }
}

class Person {
    String name;
    int age;//默认0
    //第一个构造器
    public Person(String pName, int pAge) {
        name = pName;
        age = pAge;
    }
    //第二个构造器, 只指定人名, 不需要指定年龄.
    public Person(String pName) {
        name = pName;
    }
}

在这里插入图片描述

在这里插入图片描述

课堂练习

在前面定义的Person类中添加两个构造器. ConstructorExercise.java
第一个无参构造器: 利用构造器设置所有人的age属性初始值都为18
第二个带pName和pAge两个参数的构造器: 使用每次创建Person对象的同时初始化对象的age属性值和name属性值. 分别使用不同的构造器, 创建对象.

public class ConstructorExercise {

	//编写一个main方法
	public static void main(String[] args) {
		Person p1 = new Person();//无参构造器

		//下面输出 name=null age=18
		System.out.println("p1的信息 name=" + p1.name + ", age=" + p1.age);


		Person p2 = new Person("scott", 58);//有参构造器

		//下面输出 name=scott age=58
		System.out.println("p2的信息 name=" + p2.name + ", age=" + p2.age);
	}
}

/**
	在前面定义的Person类中添加两个构造器.
	第一个无参构造器: 利用构造器设置所有人的age属性初始值都为18
	第二个带pName和pAge两个参数的构造器: 使用每次创建Person对象的同时初始化对象的age属性值和name属性值. 
	分别使用不同的构造器, 创建对象. 
 */
class Person {
	String name;//默认值 null
	int age;//默认值 0

	//第一个无参构造器: 利用构造器设置所有人的age属性初始值都为18
	public Person() {
		age = 18;
	}

	//第二个带pName和pAge两个参数的构造器: 
	//使用每次创建Person对象的同时初始化对象的age属性值和name属性值
	public Person(String pName, int pAge) {
		name = pName;
		age = pAge;
	}
}

对象创建的流程分析

●看一个案例
class Person {//类Person
          int age = 90;
          String name;
          Person(String n, int a) {
                    name = n;//给属性赋值
                    age = a;
          }
}
Person p = new Person(“小倩”, 20);

●流程分析(面试题)
1.加载Person类信息(Person.class), 只会加载一次
2.在堆中分配空间(地址)
3. 完成对象初始化 [3.1默认初始化 age=0 name=null 3.2显示初始化 age=90 name=null 3.3构造器的初始化 age=20 name=小倩]
4.把对象在堆中的地址返回给 p(p是对象名, 也可以理解成是对象的引用)
在这里插入图片描述在这里插入图片描述

在这里插入图片描述

●类定义的完善 ◀️▶️

在这里插入图片描述

5.this关键字

先看一段代码, 并分析问题 This01.java

public class This01 {

	//编写一个main方法
	public static void main(String[] args) {
        Dog dog1 = new Dog("大壮", 3);
        dog1.info();
	}
}

class Dog {

    String name;
    int age;
    /*public Dog(String dName, int dAge) {//构造器
        name = dName;
        age = dAge;
    }*/
    //如果我们构造器的形参, 能够直接写成属性名, 就更好惹
    //但是出现了一个问题, 根据变量的作用域原则
    //构造器的name 就是局部变量, 而不是属性
    //构造器的age 就是局部变量, 而不是属性
    //==> 引入this关键字来解决
    public Dog(String name, int age) {//构造器
        name = name;
        age = age;
    }

    public void info() {//成员方法, 输出属性信息
        System.out.println(name + "\t" + age + "\t");
    }
}

●什么是this
java虚拟机会给每个对象分配 this, 代表当前对象. 坦白地讲, 要明白this 不是件容易的事.

在这里插入图片描述

● 使用this解决前面变量命名问题.
具体看代码

public class This01 {

	//编写一个main方法
	public static void main(String[] args) {
        Dog dog1 = new Dog("大壮", 3);
        dog1.info();
	}
}

class Dog {

    String name;
    int age;
    /*public Dog(String dName, int dAge) {//构造器
        name = dName;
        age = dAge;
    }*/
    //如果我们构造器的形参, 能够直接写成属性名, 就更好惹
    //但是出现了一个问题, 根据变量的作用域原则
    //构造器的name 就是局部变量, 而不是属性
    //构造器的age 就是局部变量, 而不是属性
    //==> 引入this关键字来解决
    public Dog(String name, int age) {//构造器
        //this.name 就是当前对象的属性name
        this.name = name;
        //this.age 就是当前对象的属性age
        this.age = age;
    }

    public void info() {//成员方法, 输出属性信息
        System.out.println(name + "\t" + age + "\t");
    }
}

深入理解this

为了进一步理解this, 我们再看一个案例 This01.java
在这里插入图片描述
在这里插入图片描述

如何打印出this指向的地址? 答案: 在java中无法打印. 因为java程序是在虚拟机上运行的, 地址是虚拟机的地址, 没有办法直接获取到地址. 但可以使用hashcode, 可以简单地当作对象的地址, 但不是真的对象地址. 即可以使用hashCode方法简单地做一个判断.
在这里插入图片描述

使用hashcode方法看看对象的情况

public class This01 {

	//编写一个main方法
	public static void main(String[] args) {
		Dog dog1 = new Dog("旺财", 3);
		System.out.println("dog1的hahcode=" + dog1.hashCode());

		Dog dog2 = new Dog("大黄", 2);
		System.out.println("dog2的hahcode=" + dog2.hashCode());
	}
}

class Dog {
	String name;
	int age;

	public Dog(String name, int age) {//构造器
		System.out.println("this.hashCode=" + this.hashCode());
	}
} 

在这里插入图片描述


this小结: 简单地说, 哪个对象调用, this就代表哪个对象

public class This01 {

	//编写一个main方法
	public static void main(String[] args) {
		Dog dog1 = new Dog("旺财", 3);
		System.out.println("dog1的hahcode=" + dog1.hashCode());
		//dog1调用了 info方法
		dog1.info();
		
		System.out.println("====================");
		Dog dog2 = new Dog("大黄", 2);
		System.out.println("dog2的hahcode=" + dog2.hashCode());
		dog2.info();
	}
}

class Dog {
	String name;
	int age;

	public Dog(String name, int age) {//构造器
		System.out.println("this.hashCode=" + this.hashCode());
	}

	public void info() {//成员方法
		System.out.println("this.hashCode=" + this.hashCode());
	}
} 

在这里插入图片描述

注意事项和细节

1.this关键字可以用来访问本类的属性, 方法, 构造器 ThisDetail.java
2.this用于区分当前类的属性和局部变量
3.在方法的动态绑定中, this.方法名(参数列表) 和 方法名(参数列表)是等价的, 都是从运行类型开始建立查找关系.

public class ThisDetail {
	//编写一个main方法
	public static void main(String[] args) {
		T t2 = new T();
		t2.f3();
	}
}

class T {

	String name = "jack";
	int age = 23;

	//this关键字可以用来访问本类的属性
	public void f3() {
		//String name = "tom";
		//传统方式
		System.out.println("name=" + name + ", age=" + age);//tom, 23
		//也可以使用this访问属性
		System.out.println("name=" + this.name + ", age=" + age);//jack, 23
	}
}

3.访问成员方法的语法: this.方法名(参数列表)

public class ThisDetail {

	//编写一个main方法
	public static void main(String[] args) {
		T t1 = new T();
		t1.f2();
	}
}

class T {

	//细节: 访问成员方法的语法: this.方法名(参数列表)
	
	public void f1() {
		System.out.println("f1() 被调用...");
	}

	public void f2() {
		System.out.println("f2() 被调用...");
		//调用本类的f1()...
		//第一种方式
		f1();
		//第二种方式
		this.f1(); 
	}
}

4.访问构造器语法: this(参数列表) 注意只能在构造器中使用(即只能在构造器中去访问另一个构造器), 必须放在第一条语句

public class ThisDetail {

	//编写一个main方法
	public static void main(String[] args) {
		T t2 = new T();
	}
}

class T {

	/*
	细节: 访问构造器语法: this(参数列表)
	注意只能在构造器中使用(即只能在一个构造器中访问另一个构造器)

	注意: 访问构造器语法: this(参数列表): 必须放在第一条语句
	*/
	public T() {
		//这里去访问 T(Stirng name, int age) 构造器...
		this("jack", 23);
		System.out.println("T() 构造器...");
	}

	public T(String name, int age) {
		System.out.println("T(String name, int age) 构造器...");
	}
}

5.this不能在类定义的外部使用, 只能在类定义的方法中使用

方法动态绑定中this用法

public class Super01 {
      public static void main(String[] args) {
            A a = new B();
            a.cal();
      }
}
class A {
      public void cal() {
             this.sum();
            System.out.println(“A类 cal()…”);
      }
      public void sum() {
            System.out.println(“A类 sum()…”);
      }
}
class B extends A {
      public void sum() {
             System.out.println(“B类 sum()…”);
}
在这里插入图片描述

课堂练习

定义Person类, 里面有name, age属性, 并提供compareTo比较方法, 用于判断是否和另一个人相等, 提供测试类TestPerson用于测试, 名字和年龄完全一样, 就返回true, 否则返回false. TestPerson.java

public class TestPerson {

	//编写一个main方法
	public static void main(String[] args) {
		Person p1 = new Person("mary", 21);
		Person p2 = new Person("mary", 21);
		System.out.println("p1和p2比较的结果=" + p1.compareTo(p2));
	}
}

/*
	定义Person类, 里面有name, age属性, 并提供compareTo比较方法, 
	用于判断是否和另一个人相等, 提供测试类TestPerson用于测试. 
	若名字和年龄完全一样, 就返回true, 否则返回false.
*/
class Person {
	String name;
	int age;

	//构造器
	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}

	//compareTo比较方法
	public boolean compareTo(Person p) {
		//名字和年龄完全一样
		// if(p.name.equals(this.name) && p.age == this.age) {
		// 	return true;
		// } else {
		// 	return false;
		// }
		return p.name.equals(this.name) && p.age == this.age;
	}
}

第七章·课后作业

1.编写类A01, 定义方法max, 实现求某个double数组的最大值, 并返回 Homework01.java

public class Homework01 {

    //编写一个main方法
    public static void main(String[] args) {
        double[] arr = {1.3,4,2,5,2,1,3,4.2, 2.1};//null;//{};//{-1, -5, -4, -3, -2};//{};
        A01 a01 = new A01();
        Double res = a01.max(arr);
        if (res != null) {
            System.out.println("最大值=" + res);
        } else {
            System.out.println("输入的数组有误, 数组不能为null, 或者{}");
        }
    }
}

/*
编写类A01, 定义方法max, 实现求某个double数组的最大值, 并返回

思路分析
1.类名 A01
2.方法名 max
3.形参 (double[])
4.返回值 double

先完成基本功能, 再考虑代码的健壮性
 */
class A01 {

    public Double max(double[] arr) {
        //必须保证数据至少有一个元素
        if (arr != null && arr.length > 0) {
            double max = arr[0];//假设第一个值就是最大值
            for(int i = 0; i < arr.length; i++) {
                if (max < arr[i]) {
                    max = arr[i];
                }
            }
            return max;
        } else {
            return null;
        }
    }
}

2.编写类A02, 定义方法find, 实现查找某字符串是否在字符串数组中, 并返回索引, 如果找不到, 返回-1. Homework02.java

public class Homework02 {

    //编写一个main方法
    public static void main(String[] args) {
        String findStr = "赵志伟";//"赵";
        String[] str = {};//{"null", "赵志伟", "赵培竹"};
        A02 a02 = new A02();
        Integer index = a02.find(findStr, str);
        if (index != null) {
            if (index != -1) {
                System.out.println("字符串数组中存在 " + findStr);
            } else {
                System.out.println("字符串数组中不存在 " + findStr);
            }
        } else {
            System.out.println("输入的字符串 或者 字符串数组 有误");
        }
    }
}

/*
编写类A02, 定义方法find, 实现查找某字符串是否在字符串数组中, 
并返回索引, 如果找不到, 返回-1.
 
思路分析
1.类名 A02
2.方法名 find
3.形参 (String, String[])
4.返回值 int

先完成正常逻辑, 再考虑代码的健壮性
 */
class A02 {

    public Integer find(String findStr, String[] str) {
        //考虑代码的健壮性
        if (findStr != null && str != null && !"".equals(findStr) && str.length > 0) {
            //直接便利字符串数组, 如果找到, 则返回索引
            for(int i = 0; i < str.length; i++) {
                if (findStr.equals(str[i])) {
                    return i;
                }
            }
            return -1;
        } else {
            return null;
        }
    }
}

3.编写Book类, 定义方法updatePrice, 实现更改某本书的价格. 具体: 如果价格 > 150, 则更改为 150; 如果价格 > 100, 更改为100, 否则不变.Homework03.java

public class Homework03 {

    //编写一个main方法
    public static void main(String[] args) {
        /*
        1.加载Person类信息[只会加载一次]
        1.在堆中分配空间[地址]
        2.属性默认初始化 String name = null double price = 0.0
        3.属性显式初始化 String name = null double price = 0.0
        4.属性构造方法初始化 String name = "天龙八部" double price = 50.5
        5.把对象在堆中的地址返回给book对象引用
         */
        Book book = new Book("天龙八部", 1440);
        book.info();
        book.updatePrice();
        book.info();
    }
}

/*
编写Book类, 定义方法updatePrice, 实现更改某本书的价格. 
具体: 如果价格 > 150, 则更改为 150; 如果价格 > 100, 更改为100, 否则不变.

思路分析
1.类名 Book
2.属性 name, price
3.方法名 updatePrice
4.形参 ()
5.返回值 void
6.提供一个构造器
*/
class Book {

    String name;//属性 书的名字
    double price;//属性 书的价格

    public Book(String name, double price) {//构造方法 对象属性初始化
        this.name = name;
        this.price = price;
    }

    public void updatePrice() {//行为 修改价格
        //作用域: 如果方法中, 没有 price 局部变量, this.price 等价 price
        if (price > 150) {
            price = 150;
        } else if (this.price > 100) {
            this.price = 100;
        }
    }

    //显示书籍的价格情况
    public void info() {
        System.out.println("修改之后, " + this.name + "的价格为 " + this.price);
    }
}

4.编写类A03, 实现数组的复制功能copyArr, 输入旧数组, 返回一个新数组, 元素和旧数组一样.Homework04.java

public class Homework04 {

    //编写一个main方法
    public static void main(String[] args) {
        A03 a03 = new A03();
        int[] oldArr = {3, 1, 9, 4, 8, 2};
        int[] newArr = a03.copyArr(oldArr);
        //遍历newArr, 验证
        System.out.println("===返回的newArr元素情况===");
        for(int i = 0; i < newArr.length; i++) {
            System.out.print(newArr[i] + " ");
        }
    }
}

/*
编写类A03, 实现数组的复制功能copyArr, 
输入旧数组, 返回一个新数组, 元素和旧数组一样.

思路分析
1.类名 A03
2.方法名 copyArr
3.形参 (int[])
4.返回值 int[]
*/
class A03 {

    public int[] copyArr(int[] oldArr) {
        //在堆中, 创建一个长度为 oldArr.length 数组
        int[] newArr = new int[oldArr.length];
        //遍历 oldArr, 将元素拷贝至 newArr
        for(int i = 0; i < oldArr.length; i++) {
            newArr[i] = oldArr[i];
        }
        return newArr;
    }
}

5.定义一个圆类Circle, 定义属性: 半径, 提供显示圆周长功能的方法, 提供显示圆面积的方法. Homework05.java

public class Homework05 {

    //编写一个main方法
    public static void main(String[] args) {
        Circle circle = new Circle(2);
        System.out.println("circumstance=" + circle.circumstance());
        System.out.println("area=" + circle.area());
    }
}

/*
定义一个圆类Circle, 定义属性: 半径, 
提供显示圆周长功能的方法, 提供显示圆面积的方法.

1.类名 Circle
2.属性 radius
3.方法名 getCircumstance getArea
4.形参 (double)
5.返回类型 double
 */
class Circle {

    double radius;

    public Circle(double radius) {//构造器
        this.radius = radius;
    }

    public double circumstance() {//周长
        return 2 * Math.PI * radius;
    }

    public double area() {//面积
        return Math.PI * radius * radius;
    }
}

6.编程创建一个Cale类, 在其中定义2个变量表示两个操作数,定义四个方法实现求和, 差, 乘, 商 (要求除数为0的话, 要提示), 并创建两个对象, 分别测试.Homework06.java

public class Homework06 {

    //编写一个main方法
    public static void main(String[] args) {
        Cale cal = new Cale(12, 10);
        System.out.println("和=" + cal.sum());
        System.out.println("差=" + cal.sub());
        System.out.println("乘=" + cal.multi());
        Double divRes = cal.div();
        if (divRes != null) {
            System.out.println("除=" + cal.div());
        } 
    }
}

/*
编程创建一个Cale类, 在其中定义2个变量表示两个操作数,
定义四个方法实现求和, 差, 乘, 商 (要求除数为0的话, 要提示), 并创建两个对象, 分别测试

思路分析
1.类名 Cale
2.属性 num1 num2
3.方法名 sum sub multi div
4.返回值 int
5.给一个构造器
 */
class Cale {

    double num1;
    double num2;

    public Cale(double num1, double num2) {
        this.num1 = num1;
        this.num2 = num2;
    }

    //和
    public double sum() {
        return num1 + num2;
    }

    //减
    public double sub() {
        return num1 - num2;
    }

    //乘
    public double multi() {
        return num1 * num2;
    }

    //除
    public Double div() {
        //判断
        if (num2 == 0) {
            System.out.println("num2不能为0");
            return null;
        } else {
            return num1 / num2;
        }
    }
}

7.设计一个Dog类, 有名字, 颜色和年龄属性, 定义输出方法show()显示其信息. 并创建对象, 进行测试. [提示: 使用this.属性] Homework07.java 简单

public class Homework07 {

    //编写一个main方法
    public static void main(String[] args) {
        Dog dahuang = new Dog("大黄", "黄色", 3);
        dahuang.show();
    }
}

/*
设计一个Dog类, 有名字, 颜色和年龄属性, 定义输出方法show()显示其信息. 
并创建对象, 进行测试. [提示: 使用this.属性]

思路分析
1.类名 Dog
2.属性 名字, 颜色, 年龄
3.方法名 show
4.形参 ()
5.构造器
 */
class Dog {
    String name;
    String color;
    int age;

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

    //定义输出方法, 显示其信息
    public void show() {
        System.out.println("狗的名字=" + this.name + 
            " 狗的颜色=" + this.color + " 狗的年龄=" + this.age + "岁");
    }
}

8.给定一个Java程序的代码如下所示, 编译运行后, 输出结果是 ().Test.java
public class Test {
      int count = 9;
      public void count1() {
            count = 10;
            System.out.println(“count1=” + count);
      }
      public void count2() {
            System.out.println(“count1=” + count++);
      }
      public static void main(String[] args) {
            new Test().count1();
            Test test = new Test();
            test.count2();
            test.count2();
      }
}

题目解读
在这里插入图片描述在这里插入图片描述

public class Test { //公有类
    int count = 9; //属性
    public void count1() { //Test类的成员方法
        count = 10;//这个count就是属性, 改成 10
        System.out.println("count1=" + count);//10
    }

    public void count2() { //Test类的成员方法
        System.out.println("count1=" + count++);//9
    }

    //这是Test类的main方法, 任何一个类, 都可以有main方法
    public static void main(String[] args) {
        //解读
        //1. new Test() 是匿名对象, 匿名对象使用后, 就不能使用
        //2. new Test().count1() 创建好匿名对象后, 就调用count1()
        new Test().count1();
        Test test = new Test();
        test.count2();//9
        test.count2();//10
    }
}

9.定义 Music 类, 里面有音乐名name, 音乐时长time属性, 并有播放play功能和返回本身属性信息的功能方法getInfo.Homework09.java

public class Homework09 {

    //编写一个main方法
    public static void main(String[] args) {
        Music music = new Music("高山流水", 120);
        music.play();
        System.out.println("音乐信息 " + music.getInfo());
    }
}

/*
定义 Music 类, 里面有音乐名name, 音乐时长times属性, 
并有播放play功能和返回本身属性信息的功能方法getInfo.

思路分析
1.类名 Music
2.属性 name, times
3.方法名 play getInfo
4.返回类型 void String
5.构造器
 */
class Music {
    String name;
    int times;

    public Music(String name, int times) {
        this.name = name;
        this.times = times;
    }

    //播放play功能
    public void play() {
        System.out.println("音乐 " + name + " 开始播放, 音乐时长为" + times + "分钟");
    }

    //返回本身属性信息
    public String getInfo() {
        return "音乐名=" + name + " 播放时长=" + times;
    }
}

10.试写出以下代码的运行结果(101, 100, 101, 101). Homework10.java
class Demo {
      int i = 100;
      public void m() {
            int j = i++;
            System.out.println(“i=” + i);
            System.out.println(“j=” + j);
      }
}
class Test {
      public static void main(String[] args) {//运行它
            Demo d1 = new Demo();
            Demo d2 = d1;
            d2.m();
            System.out.println(d1.i);
            System.out.println(d2.i);
      }
}
题目解读
在这里插入图片描述

11.在测试方法中, 调用method方法, 代码如下. 编译正确, 试写出method方法的定义形式, 调用语句为System.out.println(method(method(10.0, 20.0), 100); Homework11.java

public class Homework11 {

    //编写一个main方法
    public static void main(String[] args) {
        Test test = new Test();
        System.out.println(test.method(test.method(1.0, 2.0), 2.0));
    }
}

/*
在测试方法中, 调用method方法, 代码如下. 
编译正确, 试写出method方法的定义形式, 
调用语句为System.out.println(method(method(10.0, 20.0), 100));

1.类名 Test
2.方法名 method
3.形参列表 (double, double)
4.返回类型 double
 */
class Test {

    public double method(double num1, double num2) {
        return num1 + num2;
    }
}

12.创建一个Employee类, 属性有(名字, 性别, 年龄, 职位, 薪水), 提供3个构造器方法, 可以初始化(1)(名字性别, 年龄, 职位, 薪水), (2)(名字, 性别, 年龄) (3)(职位, 薪水), 要求充分复用构造器 Homework12.java

public class Homework12 {

    //编写一个main方法
    public static void main(String[] args) {
        
    }
}

/*
创建一个Employee类, 属性有(名字, 性别, 年龄, 职位, 薪水), 
提供3个构造器方法, 可以初始化
(1)(名字, 性别, 年龄, 职位, 薪水), (2)(名字, 性别, 年龄) 
(3)(职位, 薪水), 要求充分复用构

1.类名 Employee
2.属性 name, gender, age, job, salary
3.构造器 Employee(String job, double salary)
		Employee(String name, char gender, int age)
		Employee(String job, double salary, String name, char gender, int age)
 */
class Employee {
	String name;
	char gender;
	int age;
	String job;
	double salary;

	//因为要求复用构造器, 因此我们先写属性少的构造器
	//职位, 薪水
	public Employee(String job, double salary) {
		this.job = job;
		this.salary = salary;
	}

	//名字, 性别, 年龄
	public Employee(String name, char gender, int age) {
		this.name = name;
		this.gender = gender;
		 this.age = age;
	}

	//名字, 性别, 年龄, 职位, 薪水
	public Employee(String job, double salary, String name, char gender, int age) {
		this(name, gender, age);//使用到 前面的 构造方法 ☆☆☆☆☆
		this.job = job;
		this.salary = salary;
	}
}

13.将对象作为参数传递给方法. Homework13.java
题目要求:
1.定义一个Circle类, 包含一个double类型的radius属性代表圆的半径, findArea()方法返回圆的面积.
2.定义一个类PassObject, 在类中定义一个方法printAreas(), 该方法的定义如下: public void printAreas(Circle c, int times) //方法签名
3.在printAreas方法中打印输出1到times之间的每个整数半径值, 以及对应的面积. 例如, times为5, 则输出半径1, 2, 3, 4, 5, 以及对应的圆面积.
4.在main方法中调用printAreas()方法, 调用完毕后输出当前半径值. 程序运行结果如图所示:

在这里插入图片描述
在这里插入图片描述

public class Homework13 {

    //编写一个main方法
    public static void main(String[] args) {
        PassObject pass = new PassObject();
        pass.printAreas(new Circle(), 5);
    }
}

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

思路分析
1.类型 Circle
2.属性 radius
3.方法名 findArea
4.返回值 double
5.形参 ()

1.类型 PassObject
2.方法名 printAreas
3.返回值 void
4.形参 (Circle, int)
 */
class Circle { //类
	double radius;//半径

	public double findArea() {
		return Math.PI * radius * radius;
	}

	//添加方法setRadius, 修改当前对象的半径值
	public void setRadius(double radius) {
		this.radius = radius;
	}
}
class PassObject {
	public void printAreas(Circle c, int times) {
		System.out.println("Radius\t\tArea");
		for(int i = 1; i <= times; i++) {//输出1到times之间的每个整数半径值
			c.setRadius(i);//修改c 对象中的半径值
			System.out.println(c.radius + "\t\t" + c.findArea());
		}
	}
}

14.Homework14.java有个人 tom设计它的成员变量, 成员方法, 可以电脑猜拳.电脑每次都会随机生成 0, 1, 2
0 表示 石头, 1 表示 剪刀, 2 表示 布. 并要可以显示 tom的输赢次数

知识点: new Random().next(3)

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

/*                                                                                                    
请编写一个猜拳的游戏                                                                                            
有个人 Tom,设计他的成员变量. 成员方法, 可以电脑猜拳. 电脑每次都会随机生成 0, 1, 2                                                    
0 表示 石头 1 表示剪刀 2 表示 布                                                                                 
并要可以显示 Tom的输赢次数(清单), 假定 玩三次.                                                                          
 */
// 测试类,主类
public class MoraGame {

    // 测试                                                                                             
    public static void main(String[] args) {
        // 创建一个玩家对象                                                                                   
        Tom t = new Tom();
        // 用来记录最后输赢的次数                                                                                
        int isWinCount = 0;

        // 创建一个二维数组,用来接收局数,Tom出拳情况以及电脑出拳情况                                                            
        int[][] arr1 = new int[3][3];
        int j = 0;

        // 创建一个一维数组,用来接收输赢情况                                                                          
        String[] arr2 = new String[3];

        Scanner scanner = new Scanner(System.in);
        for (int i = 0; i < 3; i++) {   //比赛3次                                                              
            // 获取玩家出的拳                                                                                
            System.out.println("请输入你要出的拳(0-拳头,1-剪刀,2-布):");
            int num = scanner.nextInt();
            t.setTomGuessNum(num);
            int tomGuess = t.getTomGuessNum();
            arr1[i][j + 1] = tomGuess;

            // 获取电脑出的拳                                                                                
            int comGuess = t.computerNum();
            arr1[i][j + 2] = comGuess;

            // 将玩家猜的拳与电脑做比较                                                                           
            String isWin = t.vsComputer();
            arr2[i] = isWin;
            arr1[i][j] = t.count;

            // 对每一局的情况进行输出                                                                            
            System.out.println("==========================================================");
            System.out.println("局数\t玩家的出拳\t电脑的出拳\t输赢情况");
            System.out.println(t.count + "\t" + tomGuess + "\t\t" + comGuess + "\t\t" + isWin);
            System.out.println("==========================================================\n\n\n");
            
            isWinCount = t.winCount(isWin);
        }

        // 对游戏的最终结果进行输出
        System.out.println("========================结局===========================");
        System.out.println("局数\t\t玩家的出拳\t电脑的出拳\t输赢情况");
        for (int a = 0; a < arr1.length; a++) {
            for (int b = 0; b < arr1[a].length; b++) {
                System.out.print(arr1[a][b] + "\t\t");
            }
            System.out.print(arr2[a]);
            System.out.println();
        }
		System.out.println("=====================你赢了" + isWinCount + "次=========================");
    }

}

// Tom类
class Tom {     // 核心代码  
    // 玩家出拳的类型 
    int tomGuessNum; //0,1,2
    // 电脑出拳的类型
    int comGuessNum; //0,1,2
    // 玩家赢的次数
    int winCountNum;
    // 比赛的次数
    int count = 1;   //一共比赛3次                                                                                 


    public void showInfo() {
        //....
    }

    /**
     * 电脑随机生成猜拳的数字的方法
     *
     * @return
     */
    public int computerNum() {
        Random r = new Random();
        comGuessNum = r.nextInt(3);      // 方法 返回 0-2的随机数                                                             
        // System.out.println(comGuessNum);                                                           
        return comGuessNum;
    }

    /**
     * 设置玩家猜拳的数字的方法
     *
     * @param tomGuessNum
     */
    public void setTomGuessNum(int tomGuessNum) {
        if (tomGuessNum > 2 || tomGuessNum < 0) {
            //抛出一个异常, 李同学会写,没有处理
            throw new IllegalArgumentException("数字输入错误");
        }
        this.tomGuessNum = tomGuessNum;
    }

    public int getTomGuessNum() {
        return tomGuessNum;
    }

    /**
     * 比较猜拳的结果
     *
     * @return 
     */
    public String vsComputer() {
        //比较巧
        if (tomGuessNum == 0 && comGuessNum == 1) {
            return "你赢了";
        } else if (tomGuessNum == 1 && comGuessNum == 2) {
            return "你赢了";
        } else if (tomGuessNum == 2 && comGuessNum == 0) {
            return "你赢了";
        } else if (tomGuessNum == comGuessNum) {
            return "平手";
        } else {
            return "你输了";
        }
    }

    /**
     * 记录玩家赢的次数
     *
     * @param  s 
     * @return
     */
    public int winCount(String s) {
        count++;    //控制玩的次数                                                                                   
        if ("你赢了".equals(s)) {     //统计赢的次数                                                                   
            winCountNum++;
        }
        return winCountNum;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

~ 小团子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值