第七章 面向对象编程(基础部分)——3

一、类与对象

二、成员方法

三、成员方法传参机制

四、重载(overload)

五、可变参数

1.基本概念

Java允许将同一个类中多个同名同功能参数个数不同的方法,封装成一个方法。

2.基本语法

访问修饰符 返回类型 方法名(数据类型... 形参名){
}

3.入门案例

可以计算2个数的和,3个数的和,4,5....

public class VarParameter01 {
	public static void main(String[] args) {

	HspMethod m = new HspMethod();
	System.out.println(m.sum(10, 20));//30
	System.out.println(m.sum(10, 20, 30));//60
	System.out.println(m.sum(10, 20, 30, 40));//100


	}
}

class HspMethod {
// 	//1.使用方法重载
// 	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相当于数组
	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;
	}
}

4.注意事项

(1)可变参数的实参可以为0个或任意多个。
(2)可变参数的实参可以为数组。
(3)可变参数的本质就是数组。
(4)可变参数可以和普通类型的参数一起放在形参列表,但必须保证可变参数在最后。
(5)一个形参列表中只能出现一个可变参数。

public class VarParameterDetail {
	public static void main(String[] args) {
			int[] arr = {1, 2, 3};
			T t = new T();
			t.f1(arr);
	}
}

class T {
	//(2)可变参数的实参可以为数组。
	public void f1(int... nums) {
		System.out.println("长度=" + nums.length);//3
	}

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

	}

	//(5)一个形参列表中只能出现一个可变参数。
	//下面的写法是错误的.
	// public void f3(int... nums1, double... nums2) {

	// }
}

5.课堂练习

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

public class VarParameterExercise {
	public static void main(String[] args) {

		HspMethod t = new HspMethod();
		System.out.println(t.showScore("milan", 40.1, 11.9));
		System.out.println(t.showScore("terry", 40.1, 11.9, 10.17, 10.25));

	}
}

class HspMethod {
	//返回多个数据类型就用String
	public String showScore(String name, double... scores) {
		double totalScores = 0;
		for(int i = 0; i < scores.length; i++) {
			totalScores += scores[i];
		}
		return name + "有" + scores.length + "门成绩总分为" + totalScores;
	}
}

六、作用域(非常重要)

1.基本使用

(1)在java编程中,主要的变量就是属性(成员变量)局部变量
(2)我们说的局部变量一般是在成员方法中定义的变量
(3)java中作用域的分类
        全局变量:也就是属性,作用域为整个类体
        局部变量:也就是除了属性之外的其他变量,作用域为定义它的代码块
(4)全局变量(属性)可以不赋值,直接使用,因为有默认值;局部变量必须赋值后才能使用,因为没有默认值。

public class VarScope {
	public static void main(String[] args) {


	}
}

class Cat {

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

	//全局变量(属性)可以不赋值,直接使用,因为有默认值;
	double weight; //默认值是0.0
	//局部变量必须赋值后才能使用,因为没有默认值。
	public void hi() {
		int i = 1;
		String address;
		System.out.println("i=" + i);
		//System.out.println("address=" + address); //错误:可能尚未初始化变量address
		System.out.println("weight=" + weight);

	}

	{
		int num = 100; //代码块中的变量
	}



	public void cry() {
		//1.我们说的局部变量一般是指在成员方法中定义的变量。
		//2.n 和 name 就是所说的成员变量。
		//3.n 和 name 的作用域在cry方法中。
		int n = 0;
		String name = "xiaolin";

		System.out.println("在eat方法中使用属性 age=" + age);
	}

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

2.注意事项和使用细节

(1)属性和局部变量可以重名,访问时遵循就近原则
(2)在同一个作用域中,比如在同一个成员方法中,两个局部变量,不能重名。
(3)属性生命周期较长,伴随着对象的创建而创建,伴随着对象的销毁而销毁;
        局部变量生命周期短,伴随着它所在代码块的执行而创建,伴随着代码块的结束而销毁,即在一次方法调用过程中。
(4)作用域范围不同
        全局变量/属性:可以被本类使用,或其他类使用(通过对象调用,有两种办法)。
        局部变量:只能在本类中对应的方法中使用。
(5)修饰符不同
        全局变量/属性可以加修饰符。
        局部变量不可以加修饰符。

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

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

	}
}

class T {

	//5.属性可以加修饰符(protected public private...)
	public int age = 10;//正确

	//4.第1种跨类访问对象属性的方式
	public void test() {
		//5.局部变量不能加修饰符
		//public int age = 10;//错误
		Person p = new Person();
		System.out.println(p.name); //jack
	}

	//4.第2种跨类访问对象属性的方式:将别的类创建的对象作为参数传入该方法
	public void test2(Person p) {
		System.out.println(p.name); //jack
	}

}

class Person {
	String name = "jack";

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

	public void hi() {
		//2.在同一个作用域中,比如在同一个成员方法中,两个局部变量,不能重名。
		String address = "北京";
		//String address = "上海";//错误,重复定义变量
	}
}

七、构造器

1.需求

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

2.基本介绍

构造方法又叫构造器(constructor),是类的一种特殊的方法。它的主要作用是完成对象的属性初始化。(而不是创建对象)

3.基本语法

[修饰符] 方法名(形参列表){
               方法体;
}
特点:(1)构造器的修饰符可以默认,也可以是public\protected\private.
        (2)没有返回值,也不能写void。
        (3)方法名和类名必须一样。
        (4)形参列表和成员方法一样的规则。
        (5)构造器的调用,由系统完成。即在创建对象时,系统会自动地调用该类的构造器完成对象的属性初始化。

4.快速入门

现在我们就用构造方法来完成刚才提出的问题:在创建人类的对象时,就直接指定这个对象的年龄和姓名。

public class Constructor01 {
	public static void main(String[] args) {

		Person p = new Person("xiaolin", 25);
		System.out.println("对象的属性信息:");
		System.out.println("姓名=" + p.name);
		System.out.println("年龄=" + p.age);
	}
}

class Person {
	//成员变量(属性)
	String name;
	int age;

	public Person(String pName, int pAge) {
		name = pName;
		age = pAge;
	}
}

5.注意事项和使用细节

(1)一个类可以定义多个不同的构造器,即构造器重载。
(2)构造器名和类名要相同。
(3)构造器没有返回值。
(4)构造器是完成对象的初始化,并不是构建对象。
(5)在创建对象时,系统自动地调用该类的构造器。
(6)如果程序员没有定义构造方法,系统会自动给类生成一个默认无参构造器(也叫默认构造器),比如 Dog(){},使用javap指令反编译看看。

(7)一旦定义了自己的构造器,默认构造器就覆盖了,就不能再使用默认无参构造器,除非显式的定义一下。

public class ConstructorDetail {
	public static void main(String[] args) {
		Person p1 = new Person("xiaolin", 25);//调用第1个构造方法
		Person p2 = new Person("milan");//调用第2个构造方法

		Dog dog1 = new Dog();//调用默认无参构造器,若定义了自己的构造器,默认无参构造器就无法再使用,除非显式地定义一下
		Dog dog2 = new Dog(10);//调用自己定义的构造器

	}
}

class Person {
	//成员变量(属性)
	String name;
	int age;//默认0

	//第1个构造方法
	public Person(String pName, int pAge) {
		name = pName;
		age = pAge;
	}
	//第2个构造方法:只指定姓名,不指定年龄
	public Person(String pName) {
		name = pName;
	}
}

class Dog {
	/*
	没有定义构造方法,系统会自动给类生成一个默认无参构造器(也叫默认构造器)
	Dog() {
		
		}
	 */
	public Dog(int pWeight) {

	}

	Dog() {//显式地定义一下默认无参构造器,才能再使用它

	}
}

6.课堂练习

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

public class ConstructorExercise {
	public static void main(String[] args) {

		Person p1 = new Person();//调用无参构造器
		System.out.println("p1的姓名=" + p1.name + "\np1的年龄=" + p1.age);//null 18

		Person p2 = new Person("小林", 25);
		System.out.println("p2的姓名=" + p2.name + "\np2的年龄=" + p2.age);//小林 25

	}
}

class Person {

	String name;//默认为null
	int age;//默认为0

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

	//第2个带pName和pAge两个参数的构造器
	public Person(String pName, int pAge) {
		name = pName;
		age = pAge;
	}
}

对象创建的流程分析

1.在方法区加载Person类信息(Person.class),只会加载一次。
2.在堆中分配对象空间(得到一个地址)。
3.完成对象初始化。
        (1)默认初始化 age = 0, name = null
        (2)显式初始化 age = 90, name = null
        (3)构造器的初始化 age = 20, name = 小倩
4.将对象在堆中的地址,返回给p(p是对象名,也可以理解成是对象的引用)。

八、this

1.引出this

public class This01 {
	public static void main(String[] args) {

		Dog dog1 = new Dog("大壮", 3);	
		System.out.println("dog1的hashCode=" + dog1.hashCode());//将dog1的hashCode与dog1对象的this的hashCode比较,查看是否一致
		dog1.info();
		//构造器形参为dName,dAge,输出 大壮 3
		//构造器形参为name,age,输出 null 0
		//加入this后,输出 大壮 3
		
		System.out.println("============================");
		Dog dog2 = new Dog("大黄", 2);
		System.out.println("dog2的hashCode=" + dog1.hashCode());//将dog2的hashCode与dog2对象的this的hashCode比较,查看是否一致
		dog1.info();

	}
}

//类
class Dog {

	//成员变量(属性)
	String name;
	int age;

	//构造器
	// public Dog(String dName, int dAge) {
	// 	name = dName;
	// 	age = dAge;
	// }

	/*
	构造器的输出参数名不是非常的好,如果能够将dName改成name就好了
	但是出现一个问题:根据变量的作用域就近原则
	构造器中的name为局部变量,而不是属性
	构造器中的age为局部变量,而不是属性
	----->引出this关键字来解决
	 */
	// public Dog(String name, int age) {
	// 	name = name;
	// 	age = age;
	// }

	public Dog(String name, int age) {
		//this.name 就是当前对象的属性name
		this.name = name;
		//this.age 就是当前对象的属性age
		this.age = age;
		System.out.println("构造器 this的hashCode" + this.hashCode());
	}	

	//成员方法
	public void info(){
		System.out.println("info方法 this的hashCode" + this.hashCode());
		System.out.println(name + "\t" + age + "\t");//输出的是属性的值
	}
}

2.this关键字

java虚拟机会给每个对象分配this,代表当前对象。

可以将this理解为对象的一个隐藏属性,指向对象本身。

验证对象名(dog1、dog2)指向的地址和this指向的地址是否一致?
java中无法直接获取地址,可以通过hashCode间接验证。

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

3.注意事项和使用细节

(1)this关键字可以用来访问本类的属性(this.name)、方法和构造器。
(2)this用于区分当前类的属性和局部变量。
(3)访问成员方法的语法:this.方法名(参数列表);
(4)访问构造器的语法:this(参数列表);
        注意只能在构造器中使用(只能在构造器中访问另一个构造器,必须放在第一条语句)
(5)this不能在类定义的外部使用,只能在类定义的方法中使用。

public class ThisDetail {
	public static void main(String[] args) {

		T t = new T();
		// t.f2();
		t.f3();
	}
}

class T {
	//成员变量
	String name = "jack";
	int num = 10;

	//this关键字可以用来访问本类的构造器
	//访问构造器的语法:this(参数列表);
	//注意只能在构造器中使用(只能在构造器中访问另一个构造器,必须放在第一条语句)
	public T() {//构造器
		//这里去访问T(String name, int age) 构造器
		this("xiaolin", 25);
		System.out.println("T() 构造器");
	}

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

	//this关键字可以用来访问本类的成员方法
	public void f1() {//成员方法
		System.out.println("f1 方法被调用");
	}

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

	//this关键字可以用来访问本类的属性
	public void f3() {//成员方法
		String name = "smith";
		System.out.println("name=" + name +" num=" + num);//smith 10 就近原则,这里name是局部变量,num是属性
		System.out.println("name=" + this.name +" num=" + this.num);//jack 10 都是属性
	}
}

4.课堂练习

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

public class TestPerson {
	public static void main(String[] args) {

		Person p1 = new Person("xiaolin", 25);
		Person p2 = new Person("xiaolin", 2);
		System.out.println(p2.compareTo(p1));//false

	}
}

class Person {
	String name;
	int age;

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

	public boolean compareTo(Person p) {
		//字符串比较使用equals
		// if(this.name.equals(p.name) && this.age == p.age) {
		// 	return true;
		// } else {
		// 	return false;
		// }

		return this.name.equals(p.name) && this.age == p.age;
	}
}

  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值