方法的重载、形参与实参、成员变量的封装、类的继承extends、方法的重写(override)、类对象的实例化过程、多态

文章目录

    • 一、方法的重载
      • 练习:判断下列类是否是重载
      • 练习:编写重载的类
      • 体会可变个数的形参
    • 二、方法的参数传递
    • 三、面向对象特征之一:封装和隐藏
    • 四、类的继承extends
    • 五、方法的重写override
      • 练习:在子类中重写方法,覆盖父类中的方法
    • 六、 简单类对象的实例化过程
    • 七、多态性
      • 多态性(1)
      • 多态性(2)
      • 多态性(3)
      • 虚拟方法调用(Virtual Method Invocation)
      • 多态小结
        • 子类继承父类
      • 多态性应用举例
    • 八、Object类

一、方法的重载

* 重载的概念:
	在同一个类中,允许存在一个以上的同名方法,只要他们的参数个数或者参数类型不同即可。
* 重载的特点:
	与返回值无关,只看参数列表,且参数列表必须不同。(参数个数或参数类型)。调用时,根据方法参数列表的不同来区别。

重载实例:
//返回两个整数的和

int add(int x, int y){return x + y;}
//返回三个整数的和
int add(int x, int y, int z){return x+y+z;}
//返回两个整数的和 
double add(double x, double y){return x+y;}

练习:判断下列类是否是重载

与void show(int a, char b, double c){ } 构成重载的有:

a) void show(int x, char y, double z){ }		//不构成重载,因为3个参数类型相同,虽然参数名不相同。
b) int show(int a, double b, char c) { }			//构成重载,因为3个参数类型不同,(顺序位置不同即可)
c) void show(int a, double c, char b){ }		//构成重载,因为3个参数类型不同,(顺序位置不同即可)
d) boolean show(int c, char b){ }					//重载
e) void show(double c){ }							//重载
f) void shows(int x ,char y, double z){ }		//非重载
g) void shows() {double c}							//非重载,因为方法名不一样

练习:编写重载的类

* 编写程序,定义三个重载方法并调用。方法名为mOL。
- 三个方法分别接受一个int参数、两个int参数、一个字符串参数。分别执行平方运算并输出结果,输出字符串信息。
- 在主类main()方法中分别用参数区别调用三个方法
public class Test {	//类名的首字母要大写
	
	public static void main(String[] args){
		Test t = new Test ();
//		t.mOL(2);
//		t.mOL(3, 4);
//		t.mOL("方法重载mOL");
	}
		public void mOL(int i){
			System.out.println(i * i * i);
		}	
		
		public void mOL(int x, int y){
			System.out.println(x * y);
		}
		public void mOL(String s){
			System.out.println(s);
		}		
}
定义三个重载方法max(),第一个方法求两个int值中的最大值,第二个方法求两个double值中的最大值,并分别调用三个方法。
public class Test {	//类名的首字母要大写
	
	public static void main(String[] args){
		Test t = new Test ();
		t.max(3,4);
		t.max(5.5, 6.6);
		t.max(5, 6, 7);
	}
		public void max(int x, int y){
			System.out.println(x > y ? x : y);
		}	
		
		public void max(double x, double y){
			System.out.println(x > y ? x : y);
		}
		
		public void max(double m, double n, double k){
			System.out.println(m > n ? (m > k ? m : k):(n > k ? m : k));
		}		
}

体会可变个数的形参

* 下面采用数组形参来定义方法
	- public static void test(int a, String[] books);
* 以可变个数形参来定义方法
	- public static void test(int a, String...books);

说明:

1.可变参数:方法名参数部分指定类型的参数个数是可变多个
2.声明方式:方法名(参数的类型名....参数名)
3.可变参数方法的使用与方法参数部分使用数字组是一致的
4.方法的参数部分有可变形参,需要放在形参声明的最后 ,
	如 可以 public void printInfol(int i, String... args)
	但不可以 public void printInfol(String... args, int i)
public class Person {
	/**
	 * 用数组的方式来传递可变个数的参数
	 * 如果没有参数,就要定义一个空数组或者是null
	 * @param args
	 */

	public void printInfo(String[] args){
		
		for(int i = 0; i < args.length; i++){
			System.out.println(args[i]);
		}
	}
	/**
	 *用java特有的...的方式来传递可变个数的参数,这种参数在使用时与数组的使用方式相同
	 *如果没有参数就可以不填
	 *这种...代表可以传递0到多个参数
	 *如果一个方法有多个的形参(...这种的参数)一定要放在所有的参数最后
	 *可以 public void printInfol(int i, String... args)
	 *但不可以 public void printInfol(String... args, int i)
	 */
	public void printInfol(String...args){
		for(int i = 0; i < args.length; i++){
			System.out.println(args[i]);
		}
	}
}
public class Test {	//类名的首字母要大写
	
	public static void main(String[] args){
		Person p = new Person();
//		String[] ss = new String[]{"张三","11岁"};
//		p.printInfo(ss);
		String[] ss1 = new String[]{"北京市867","1314521","12345678910"};
//		p.printInfo(ss1);
		
		p.printInfol("李四","23","男");
		
		String[] ss2 = new String[]{"北京市867","1314521","12345678910"};

		p.printInfol(ss1);
		p.printInfol(ss2);//也能正常调用,即形参长度可变
		p.printInfol();		//...的方式没有参数可以不填
		p.printInfo(null);	//数组的方式,没有参数要写null
	}
}

二、方法的参数传递

* 方法,必须有其所在类或对象调用才有意义。若方法含有参数:
* 形参:方法声明时的参数
* 实参:方法调用时实际传递给形参的参数值

* java的实参如何传入方法呢?
 	- java里方法的参数传递方式只有一种:值传递。即将实际参数值的副本(复制品)传入方法内,而参数本身不受影响

方法的重载、形参与实参、成员变量的封装、类的继承extends、方法的重写(override)、类对象的实例化过程、多态_第1张图片


public class Test {	//类名的首字母要大写
	/**
	*先执行int a = 0; 在栈中开辟一块内存,地址就是AD8500,存的值是0
	*调用swap方法,执行int i部分,在栈中开辟一块内存,地址是AD8600,
	*值就是从a那里复制过来的值0,执行swap的方法体里面的代码,i=6,把i在栈中的值再改成
	*6,最终i在栈中的值就是6。
	*总之,基本数据类型在参数传递的过程中,就是把实参的值赋值到形参上
	*/
	public static void swap(int i){
		i = 6;
		System.out.println("swap方法中的参数i的值:" + i);
	}
	
	public static void main(String[] args){
		int a = 0;
		swap(a);
		System.out.println("main方法中的a的值:" + a);
	}
}

上述代码输出: 6 0
说明java中的参数传递是值传递
方法的重载、形参与实参、成员变量的封装、类的继承extends、方法的重写(override)、类对象的实例化过程、多态_第2张图片


public class Test {	//类名的首字母要大写
	
	public static void swap(DataSwap ds1){  //形参为DataSwap ds1
		ds1.a = 6;
		System.out.println("在swap方法中,dsl.a的值是:" + ds1.a);
	}
	public static void main(String[] args){
		DataSwap ds = new DataSwap(); 		
		//把new DataSwap()存到堆内存中,其在堆中的地址为BE2500,
		//ds为引用对象,把ds存到栈中,地址是AD9500,值为new DataSwap()在堆中的地址BE2500
		System.out.println("调用swap方法之前,ds.a的值是:" + ds.a);
		
		swap(ds);//调用swap()方法,先给ds1引用对象保存到栈中,ds1在栈中的地址是AD9600,存的值来源于实参(ds),值为ds的栈中存的值
		
		System.out.println("调用swap方法之后,ds.a的值是:" + ds.a);
		//
	}
}

方法的重载、形参与实参、成员变量的封装、类的继承extends、方法的重写(override)、类对象的实例化过程、多态_第3张图片

三、面向对象特征之一:封装和隐藏

* 使用private关键字对成员变量进行封装
* 使用者对内部定义的属性(对象的成员变量)的直接操作会导致数据错误、混乱或安全性问题。
* Java中通过将数据声明为私有的private,再提供公共的public方法:getXxx()和setXxx()实现以下目的:
	- 隐藏一个类中不需要对外提供的实现 细节;
	- 使用者只能通过实现制定好的方法来访问数据,可以方便地加入控制逻辑,限制对属性的不合理操作;
	- 便于修改代码,增强代码的可维护性。
package day06;

public class Person {
//	public int age;
	
	//所以我们需要对这样不能让调用者随意使用的属性做封装和隐藏
	//封装和隐藏步骤:①私有化变量。②写一个与变量相关联的函数来专门规定此变量有哪些属性限制
	private int age;	//①
	
	public void printAge(){
		System.out.println("年龄:" + age);
	}
	
	public void setAge(int a){	//②
		if(a <= 150 && a >= 0){
			age = a;
		}else{
			System.out.println("输入的年龄:" + a + "不合法");
		}
	}
}
package day06;
import day06.Person;
public class Test {
	public static void main(String[] args){
		Person p = new Person();
		p.setAge(100);	//这样的情况,程序是对的,能执行,但是不符合正常逻辑
		//像这种情况,是把类的属性开放出来,让调用者随意使用,这样会有问题,
		//所以我们需要对这样不能让调用者随意使用的属性做封装和隐藏
		p.printAge();
	}		

**4.1 面向对象特征之二:继承 extends
4.2 方法的重写(override)
4.3 四种访问权限修饰符
4.4 关键字super
4.5 子类对象实例化过程
4.6 面向对象特征之三:多态
4.7 object类、包装类 **

文章目录

    • 一、方法的重载
      • 练习:判断下列类是否是重载
      • 练习:编写重载的类
      • 体会可变个数的形参
    • 二、方法的参数传递
    • 三、面向对象特征之一:封装和隐藏
    • 四、类的继承extends
    • 五、方法的重写override
      • 练习:在子类中重写方法,覆盖父类中的方法
    • 六、 简单类对象的实例化过程
    • 七、多态性
      • 多态性(1)
      • 多态性(2)
      • 多态性(3)
      • 虚拟方法调用(Virtual Method Invocation)
      • 多态小结
        • 子类继承父类
      • 多态性应用举例
    • 八、Object类

四、类的继承extends

** 为描述和处理个人信息,定义Person类:**
方法的重载、形参与实参、成员变量的封装、类的继承extends、方法的重写(override)、类对象的实例化过程、多态_第4张图片方法的重载、形参与实参、成员变量的封装、类的继承extends、方法的重写(override)、类对象的实例化过程、多态_第5张图片此时在Student类里可以直接继承一部分Person类里的属性,从而达到减少代码量的目的

package day7
public class Person(){
	int age;
	String name;
	int sex;
	
	public void showInfo(){
		System.out.println(this.age);//this. 调用类成员变量
		System.out.println(this.name);
		System.out.println(this.sex);
	}
}
public class Student extends Person { //Student类 继承了 Person类的属性
	String school;
	
	public void showInfo(){
		System.out.println(this.age);//由于继承了Person类里的属性,所以可以直接调用类成员变量age
		System.out.println(this.name);
		System.out.println(this.sex);
		System.out.println(this.school);
	}
}

方法的重载、形参与实参、成员变量的封装、类的继承extends、方法的重写(override)、类对象的实例化过程、多态_第6张图片
方法的重载、形参与实参、成员变量的封装、类的继承extends、方法的重写(override)、类对象的实例化过程、多态_第7张图片不要仅为了获取其他类中某个功能而去继承,还要考虑类之间的逻辑关系
方法的重载、形参与实参、成员变量的封装、类的继承extends、方法的重写(override)、类对象的实例化过程、多态_第8张图片子类不是父类的子集,而是父类的扩展
方法的重载、形参与实参、成员变量的封装、类的继承extends、方法的重写(override)、类对象的实例化过程、多态_第9张图片
==java只支持单继承,不支持多继承 ==
方法的重载、形参与实参、成员变量的封装、类的继承extends、方法的重写(override)、类对象的实例化过程、多态_第10张图片
方法的重载、形参与实参、成员变量的封装、类的继承extends、方法的重写(override)、类对象的实例化过程、多态_第11张图片

package day7;

public class ManKind {
	int sex;
	int salary;
	//下面设置set、get方法
	public int getSex() {
		return sex;
	}

	public void setSex(int sex) {
		this.sex = sex;
	}

	public int getSalary() {
		return salary;
	}

	public void setSalary(int salary) {
		this.salary = salary;
	}

	public void manOrWoman(){
		if (this.sex == 1)
			System.out.println("man");
		else if(this.sex == 0)
			System.out.println("woman");
	}
	
	public void employeed(){
		if(this.salary == 0)	
			System.out.println("no job");
		else if(this.salary == 1)
			System.out.println("job");		
	}
}
package day7;

public class Kids extends ManKind{//继承ManKind里的set、salary类成员变量
	int yearsOld;
	//之后生成yearsOld的get、set方法
	public int getYearsOld() {
		return yearsOld;
	}

	public void setYearsOld(int yearsOld) {
		this.yearsOld = yearsOld;
	}

	public void printAge(){
		System.out.println(this.yearsOld);
	}
	
	public static void main(String[] args){
		Kids someKid = new Kids();
		someKid.setSex(0);
		someKid.setSalary(100);
		
		someKid.manOrWoman();
		someKid.employeed();
	}
}

方法的重载、形参与实参、成员变量的封装、类的继承extends、方法的重写(override)、类对象的实例化过程、多态_第12张图片

五、方法的重写override

* 定义:在子类中可以根据需要对从父类中继承来的方法进行改造,也称方法的重置、覆盖。在程序执行时,子类的方法将覆盖父类的方法。
	* 要求:
	 1. 重写方法必须和被重写方法具有相同的方法名称、参数列表和返回值类型。
	 2. 重写方法不能使用比被重写方法更严格的访问权限。
	 3. 重写和被重写的方法须同时为static的,或同时为非static的。
	 4. 子类方法抛出的异常不能大于父类被重写方法的异常。
	通过Alt+/来调出需要重写的方法

练习:在子类中重写方法,覆盖父类中的方法

1. 如果现在父类的一个方法定义成private访问权限,在子类中将此方法声明为default访问权限,name这样还叫重写吗?
		答:不叫了,子类不能访问父类私有的方法。
2. 修改练习1.1中定义的类kids,在kids中重新定义employed()方法,覆盖父类ManKind中定义的employed()方法,输出“Kid should study and no job.”
package day7;

public class ManKind {
	int sex;
	int salary;
	//下面设置set、get方法
	public int getSex() {
		return sex;
	}

	public void setSex(int sex) {
		this.sex = sex;
	}

	public int getSalary() {
		return salary;
	}

	public void setSalary(int salary) {
		this.salary = salary;
	}

	public void manOrWoman(){
		if (this.sex == 1)
			System.out.println("man");
		else if(this.sex == 0)
			System.out.println("woman");
	}
	
	public void employeed(){
		if(this.salary == 0)	
			System.out.println("no job");
		else if(this.salary == 1)
			System.out.println("job");		
	}
}
package day7;

public class Kids extends ManKind{//继承ManKind里的set、salary类成员变量
	int yearsOld;
	//之后生成yearsOld的get、set方法
	public int getYearsOld() {
		return yearsOld;
	}

	public void setYearsOld(int yearsOld) {
		this.yearsOld = yearsOld;
	}

	public void printAge(){
		System.out.println(this.yearsOld);
	}
	
	public static void main(String[] args){
		Kids someKid = new Kids();
		someKid.setSex(0);
		someKid.setSalary(100);
		
		someKid.manOrWoman();
		someKid.employeed();
	}
	
	@Override
		public void employeed() {	
			System.out.println("Kid should study and no job.");
		}//重写
}

六、 简单类对象的实例化过程

方法的重载、形参与实参、成员变量的封装、类的继承extends、方法的重写(override)、类对象的实例化过程、多态_第13张图片方法的重载、形参与实参、成员变量的封装、类的继承extends、方法的重写(override)、类对象的实例化过程、多态_第14张图片

七、多态性

多态性(1)

* 多态性在Java中的两种体现:
  1. 方法的重载(overload)和重写(overwrite)。
     - 重载:本类中的同名方法,体现相同的名称,方法实现不同的逻辑。
     - 重写:子类对父类方法的覆盖,字类可以使用和父类相同的方法名,覆盖掉父类的逻辑。
       例如:父类的方法想修改逻辑,但有别的代码在调用父类的方法,可以考虑用子类继承父类,然后重写父类的方法。
  2. 对象的多态性--- 可以直接应用在抽象类和接口上。
	 - Java引用变量有两个类型:编译时类型和运行时类型。编译时类型由声明该变量的类型决定,运行时类型由世纪赋给该变量的对象决定。
	如: Student stu = new Student();  中
		Student stu 为编译期类型, new Student();  为先把new stu 放在堆内存里,再把堆内存中的地址放在栈中。这个过程就叫运行时多态。
	如:List list = new ArrayList<>();中,List是接口,ArrayList是实现类。这就体现了多态性
     - 若编译时类型和运行时类型不一致,就会出现多态。(对象的多态)

多态性(2)

Person p = new Person();
Student s = new Student();
//以上是正常情况
Person e = new Student(); //父类的引用对象可以指向子类的实例

Person p = new Person();
p = new Student();
//问题? 当前这个引用对象p引用的是哪个对象实例?
* 对象的多态--在java中,子类的对象可以替代父类的对象使用
   - 一个变量只能有一种确定的数据类型
   - 一个引用类型变量可能指向(引用)多种不同类型的对象
* 子类可看作是特殊的父类,所以父类类型的引用可以指向子类的对象:向上转型(upcasting)

多态性(3)

* 一个引用类型变量如果声明为父类的类型,但实际引用的是子类对象,那么该变量就不能再访问子类中添加的属性和方法。
Student s = new Student();
s.school = "xxx";
Person e = new Student();//向上转型
e.school = "xxxx";//报错,Person里没有school属性,因而编译错误。

属性是在编译时确定的,编译时e为Person类型,没有school成员变量,因而编译错误。
以上是对成员变量来说,而对方法来说就不是这样了!

虚拟方法调用(Virtual Method Invocation)

正常的方法调用

		Person = new Person():
		p.getInfo();
		Student s = new Student();
		s.getInfo();

虚拟方法调用(多态情况下)

		Person e = new Student;//编译时e为Person类型,而方法的调用实在运行时确定的,所以调用的是Student类的getInfo() 方法。
		e.getInfo();//调用Student类的getInfo() 方法

编译时类型和运行时类型
编译时e为Person类型,而方法的调用是在运行时确定的,所以调用的是Student类的getInfo() 方法。—动态绑定。

多态小结

* 前提:
	- 需要存在继承或者实现关系
	- 要有覆盖操作
* 成员方法:
	- 编译时:要查看引用变量所属的类中是否有所调用的方法。
	- 运行时:调用实际对象所属的类中的重写方法。
* 成员变量:
  	- 不具备多态性,只看引用变量所属的类。

子类继承父类

* 若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类里的同名方法,系统将不可能把父类里的方法转移到子类中
* 对于实例变量则不存在这样的现象,即使子类里定义了与父类完全相同的实例变量,这个实例变量仍然不可能覆盖父类中定义的实例变量。

多态性应用举例

  • 方法声明的形参类型为父类类型,可以使用子类的对象作为实参调用该方法。
    方法的重载、形参与实参、成员变量的封装、类的继承extends、方法的重写(override)、类对象的实例化过程、多态_第15张图片

八、Object类

- Object类是所有Java类的根父类
- 如果在类的声明中未使用extends关键字指明其父类,则默认父类为Object类

	public class Person{
	...
	}
等价于:
	public class Person extends Object{
	...
	}

多层继承,处于最高层的父类一定是Object类
例:

public void test(Object obj){		//基类
}

	public static void main(String[] args){
		Test t = new Test();
		Person p = new Person();
		Student s = new Student();
		t.test(p);	//由于Object是所有类的基类,所以怎么传递参数都可以。
		t.test(s);	//由于Object是所有类的基类,所以怎么传递参数都可以。
		t.test(new Kk());	//由于Object是所有类的基类,所以怎么传递参数都可以。
	}

你可能感兴趣的:(JavaSE)