七:面向对象(中)

00、Eclipse中的快捷键

package com.atguigu.java;

import java.sql.Date;
import java.util.ArrayList;
import java.util.HashMap;

/*
 * Eclipse中的快捷键:
 * 1.补全代码的声明:alt+/
 * 2.快速修复: ctrl + 1
 * 3.批量导包:ctrl+shift+o
 * 4.使用单行注释: ctrl+/
 * 5.使用多行注释:ctrl+shift+/
 * 6.取消多行注释:ctrl+shiift+\
 * 7.复制指定行的代码:ctrl+down 或 ctrl+up
 * 8.删除指定行的代码:ctrl+d
 * 9.上下移动代码:alt+up 或 alt+down
 * 10.切换到下一行代码空位:shift+enter
 * 11.切换到上一行代码空位:ctrl+shift+enter
 * 12.如何查看源码:ctrl+选中指定的结构 或 ctrl+shift+t
 * 13.退回到前一个编辑的页面:alt+left
 * 14.进入到下一个编辑的页面(针对于上面那条来说的):alt+right
 * 15.光标选中指定的类,查看继承树结构:ctrl+t
 * 16.复制代码:ctrl+c
 * 17.撤销:ctrl+z
 * 18.反撤销:ctrl+y
 * 19.剪贴:ctrl+x
 * 20.粘贴:ctrl+v
 * 21.保存:ctrl+s
 * 22.全选:ctrl+a
 * 23.格式化代码:ctrl+shift+f
 * 24.选中数行,整体往后移动:tab
 * 25.选中数行整体往前移动:shift+tab
 * 26.在当前类中,显示类结构,并支持搜索指定的方法、属性等:ctrl+o
 * 27.批量修改指定的变量名、方法名、类名等:alt+shift+r
 * 28.选中的结构的大小写的切换:变成大写:ctrl+shift+x
 * 29.选中的结构的大小写的切换:变成小写:ctrl+shift+y
 * 30.调出生成getter/setter/构造器等结构:alt+shift+s
 * 31.显示当前选择资源(工程or文件)的属性:alt+enter
 * 32.快速查找:参照选中的Word快速定位到下一个:ctrl+k
 * 
 * 33.关闭当前窗口:ctrl+w
 * 34.关闭所有的窗口:ctrl+shift+w
 * 35.查看指定的结构使用过的地方:ctrl+alt+g
 * 36.查找与替换:ctrl+f
 * 37.最大化当前的View:ctrl+m
 * 38.直接定位到当前行的首位:home
 * 39.直接定位到到当前行的末位:end
 * 
 * 
 * 
 * 
 */
public class EclipseKeys_1 {

	public static void main(String[] args) {

		final double pi = 3.14;
		String s = new String();
		String str = new String();
		char c = str.charAt(0);

		String string = new String();
		int num = 1;

		ArrayList list1 = new ArrayList();
		list1.add(123);
		list1.add(123);
		list1.add(123);
		list1.add(123);

		HashMap map = null;

		

		Date date = new Date(434334L);

	}
}

class student {
	private int number;
	private String name;
	public int getNumber() {
		return number;
	}
	public void setNumber(int number) {
		this.number = number;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public student(int number, String name) {
		
		this.number = number;
		this.name = name;
	}
	public student() {
		
	}
	

}

01、继承性的使用与理解

1、Person 类

package com.atguigu.java;

/*
 * 为描述和处理个人信息,定义类 Person
 */
public class Person{
	
	String name;
	private int age;
	
	public Person(){
		
	}
	
	public Person(String name,int age){
		this.name = name;
		this.age = age;
	}
	
	public void eat(){
		System.out.println("吃饭");
		sleep();
	}
	
	private void sleep(){
		System.out.println("睡觉");
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
	
}

2、Student 类

package com.atguigu.java;


/*
 * 为描述和处理学生信息,定义类 xuesheng
 */

public class xuesheng extends Person {

//	String name;
//	int age;
	String major;
	
	public xuesheng(){
		
	}
	
	public xuesheng(String name,int age,String major){
		this.name = name;
//		this.age = age;
		this.setAge(age);
		this.major = major;
	}
	
//	public void eat(){
//		System.out.println("吃饭");
//	}
//	
//	public void sleep(){
//		System.out.println("睡觉");
//	}
	
	public void study(){
		System.out.println("学习");
	}
	
	public void show(){
		System.out.println("name:" + name + ",age = " + getAge());
	}

}

3、测试类

package com.atguigu.java;

import org.junit.Test;

/*
 * 面向对象的特征二:继承性
 * 
 * 为什么要有继承?
 * 		多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,
 * 		那么多个类无需再定义这些属性和行为,只要继承那个类即可。
 *  * 一、继承性的好处
 * ① 减少了代码的冗余,提高了代码的复用性;
 * ② 便于功能的扩展;(当子类们都需要添加相同的功能时,如吃饭,可以在父类中添加)
 * ③ 为之后多态性的使用,提供了前提。
 * 
 * 二、继承性的格式
 * 	class A extends B{}
 *  A:子类、派生类、subclass
 *  B:父类、超类、基类、superclass
 *  
 *  2.1 体现:一旦子类 A 继承父类B以后,子类 A 中就获取了父类 B 中声明的所有的属性和方法
 * 		特别的,父类中声明为 private 的属性或方法,子类继承父类以后,仍然认为获取了父类中私有的结构。
 * 		只是因为封装性的影响,使得子类不能直接调用父类的结构而已。
 * (属性是通过getset来使用;方法是可以放在其他方法中,通过调用该方法间接调用)
 * 		封装性是想解决结构可见性的问题,继承性是解决拿到父类中的结构的问题,继承性是
 * 	可以拿到父类所有的属性和方法,但是拿到后能不能调用,还得看封装性
 *  2.2 子类继承父类以后,还可以声明自己特有的属性或方法,实现功能的拓展。
 *  	子类和父类的关系:不同于子集与集合的关系。
 *  	extends:延展、扩展
 * 
  三、Java 中关于继承性的规定:
 *  	1.一个类可以被多个类继承
 *  	2.Java 中类的单继承性:一个类只能有一个父类
 *  	3.子父类是相对的概念。(类可以多层继承)
 *  	4.子类直接继承的父类,称为:直接父类。间接继承的父类,称为,间接父类。
 *  	5.子类继承父类后,就获取了直接父类以及所有间接父类中声明的属性和方法。
 * 	
 * 四、1.如果我们没有显式的声明一个类的父类的话,则此类继承于 java.lang.Object 类(object有时候也被称为根父类)
 * 	  2.所有的 java 类(除 java.lang.Object 类之外)都直接或间接地继承于 java.lang.Object 类;
 * 	  3.意味着,所有的 java 类具有 java.lang.Object 类声明的功能。
 * 
 */
public class ExtendsTest {

	
	@Test//光标一样导包
	public void testExtends()
	{
		//添加要测试的内容
	}
	public static void main(String[] args) {
		Person p1 = new Person();
//		p1.age = 1;
		p1.eat();
		System.out.println("********************");
		
		xuesheng s1 = new xuesheng();//s1指向的堆空间的对象中也有父类的成员
		s1.eat();
//		s1.sleep();
		s1.name = "Tom";
		
		s1.setAge(10);
		System.out.println(s1.getAge());
		
		s1.breath();
		
		Creature c1=new Creature();
		//c1.可以看到可以调用很多方法
		
	}
}



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

4、Java 中关于继承性的规定

/*
 * 面向对象的特征二:继承性
 * 
 * 为什么要有继承?
 * 		多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,
 * 		那么多个类无需再定义这些属性和行为,只要继承那个类即可。
 *  * 一、继承性的好处
 * ① 减少了代码的冗余,提高了代码的复用性;
 * ② 便于功能的扩展;(当子类们都需要添加相同的功能时,如吃饭,可以在父类中添加)
 * ③ 为之后多态性的使用,提供了前提。
 * 
 * 二、继承性的格式
 * 	class A extends B{}
 *  A:子类、派生类、subclass
 *  B:父类、超类、基类、superclass
 *  
 *  2.1 体现:一旦子类 A 继承父类B以后,子类 A 中就获取了父类 B 中声明的所有的属性和方法
 * 		特别的,父类中声明为 private 的属性或方法,子类继承父类以后,仍然认为获取了父类中私有的结构。
 * 		只是因为封装性的影响,使得子类不能直接调用父类的结构而已。
 * (属性是通过getset来使用;方法是可以放在其他方法中,通过调用该方法间接调用)
 * 		封装性是想解决结构可见性的问题,继承性是解决拿到父类中的结构的问题,继承性是
 * 	可以拿到父类所有的属性和方法,但是拿到后能不能调用,还得看封装性
 *  2.2 子类继承父类以后,还可以声明自己特有的属性或方法,实现功能的拓展。
 *  	子类和父类的关系:不同于子集与集合的关系。
 *  	extends:延展、扩展
 * 
  三、Java 中关于继承性的规定:
 *  	1.一个类可以被多个类继承
 *  	2.Java 中类的单继承性:一个类只能有一个父类
 *  	3.子父类是相对的概念。(类可以多层继承)
 *  	4.子类直接继承的父类,称为:直接父类。间接继承的父类,称为,间接父类。
 *  	5.子类继承父类后,就获取了直接父类以及所有间接父类中声明的属性和方法。
 * 	
 * 四、1.如果我们没有显式的声明一个类的父类的话,则此类继承于 java.lang.Object 类(object有时候也被称为根父类)
 * 	  2.所有的 java 类(除 java.lang.Object 类之外)都直接或间接地继承于 java.lang.Object 类;
 * 	  3.意味着,所有的 java 类具有 java.lang.Object 类声明的功能。
 * 
 */

5、将上述 Person 类改为如下

public class Person extends Creature {
    ...
}

6、Creature 类

package com.atguigu.java;

public class Creature {//光标在上,ctrl{t查看继承树,或者在ExtendsTest中定义一个Creature对象c1,再c1.即可看到object中的很多方法
	
	public void breath() {
		System.out.println("breath");
	}
}

在这里插入图片描述

1.1、继承性练习

1、练习1

在这里插入图片描述

ManKind类

package com.atguigu.exer;
/*
 * 定义一个ManKind类,包括
 * 成员变量int sex和int salary;
 * 方法void manOrWoman():根据sex的值显示“man”(sex==1)或者“woman”(sex==0);
 * 方法void employeed():根据salary的值显示“no job”(salary==0)或者“job”(salary!=0)。
 * 
 */
public class ManKind {
	private int sex;
	private int salary;
	
	public ManKind() {
	
	}
	

	public ManKind(int sex, int salary) {
		this.sex = sex;
		this.salary = salary;
	}


	public void manOrWoman() {
		if(sex==1) {
			System.out.print("man");
		}else if(sex==0) {
			System.out.print("woman");
		}
	}
	
	
	public void employeed()
	{
		if(salary==0)
		{
			System.out.println("no job");
		}else if(salary!=0)
		{
			System.out.println("job");
		}
		
		//或
		/*
		 * String jobInfo=(salary==0)?"no job":"job"; System.out.println(jobInfo);
		 */
	}


	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;
	}
	
	
}

Kids类

package com.atguigu.exer;

/*
 * 定义类Kids继承ManKind,并包括
 * 成员变量int yearsOld;
 * 方法printAge()打印yearsOld的值
 * 
 */
public class Kids extends ManKind {//javabean
	private int yearsOld;
	
	public Kids(int yearsOld) {
		this.yearsOld = yearsOld;
	}

	

	public Kids() {
		super();
	}



	public void printAge()
	{
		System.out.println("I am "+yearsOld+" years old");
	}

	public int getYearsOld() {
		return yearsOld;
	}

	public void setYearsOld(int yearsOld) {
		this.yearsOld = yearsOld;
	}
	/*
	 * 2.修改练习1.2中定义的类Kids,在Kids中重新定义employeed()方法,
	 * 	  覆盖父类ManKind中定义的employeed()方法,
	 *   输出“Kids should study and no job.”
	 */
	
		public void employeed() {
			System.out.println("Kids should study and no job.");
		}
}

KidsTest

package com.atguigu.exer;

/*
 * 定义类KidsTest,在类的main方法中实例化Kids的对象someKid,
 * 用该对象访问其父类的成员变量及方法。
 * 
 */
public class KidsTest {
	//内存图:堆空间中有父类的salary、sex 和 子类的yearsOld
	//(父类的salary、sex 虽然在父类中是private但是在子类实例化的时候也会加载到堆空间中)

	public static void main(String[] args) {
		Kids someKid=new Kids(12);
		
		someKid.printAge();
		
		someKid.setSalary(0);
		someKid.setSex(1);
		
		someKid.employeed();
		someKid.manOrWoman();
		
		
		
	}
}

2、练习2

在这里插入图片描述

package com.atguigu.exer1;

public class Circle {
	private double radius;//半径
	
	public Circle()
	{
		radius=1.0;
	}

	public double getRadius() {
		return radius;
	}

	public void setRadius(double radius) {
		this.radius = radius;
	}
	
	//返回圆的面积
	public double findArea()
	{
		return Math.PI*radius*radius;
	}
}

Cylinder类

package com.atguigu.exer1;

import static java.lang.Math.*;

public class Cylinder extends Circle{

	private double length;
	
	public Cylinder()
	{//默认的super();
		length=1;
	}

	public double getLength() {
		return length;
	}

	public void setLength(double length) {
		this.length = length;
	}
	
	//返回圆的体积
	public double findVolume()
	{
		//return PI*getRadius()*getRadius()*length;
		//return findArea()*getLength();//被重写了,故不再是底面积了
		return super.findArea()*getLength();//子类中的方法调用父类中被重写的方法,要用super关键字
	}
	@Override
	public double findArea() {//返回圆柱的表面积
		return PI*getRadius()*getRadius()*2+2*PI*getRadius()*getLength();
	}
	
}

测试类

package com.atguigu.exer1;

public class CylinderTest {
	public static void main(String[] args) {
		
		Cylinder cy=new Cylinder();
		
		cy.setRadius(2.1);
		cy.setLength(3.4);
		double volume=cy.findVolume();
		System.out.println("圆柱的体积为: "+volume);
		
		//没有重写findArea()时;
//		double area=cy.findArea();
//		System.out.println("底面圆的面积: "+area);
		
		//重写findArea()后:
		double area=cy.findArea();
		System.out.println("圆柱的表面积: "+area);
		
//		构造器:
		
		System.out.println("*************");
		Cylinder cy1=new Cylinder();//调用的是子类的空参构造器,因为在该子类的构造器中有一个默认的super();
		//造对象的时候就执行super,然后奔到父类的构造器中执行了radius=1;先把半径初始化,然后回到父类在再将length初始化
		
		double volume1=cy1.findVolume();
		System.out.println("圆柱的体积为: "+volume1);//不是0,而是3.14……
	}
}

1.2、Debug

DebugTest

package com.atguigu.java;

/*
 * 如何调试程序:
 * 1.System.out.println().
 * 2. Eclipse-Debug调试
 * 
 */
public class DebugTest
{
	public static void main(String[] args)
	{
		int i=10;
		int j=20;

		System.out.println("i= "+i+",j= "+j);

		DebugTest test=new DebugTest();
		int max= test.getMax(i,j);

		System.out.println("max= "+max);
	}

	private int getMax(int k,int m)
	{
		int max=0;
		if(k<m)
		{
			max=k;
		}else
		{
			max=m;
		}
		return max;
	}

}

DebugTest1

package com.atguigu.java;

public class DebugTest1
{
	public static void main(String[] args)
	{
		int[] arr=new int[]{1,2,3,4,5};
		System.out.println(arr);//地址值ֵַ

		char[] arr1=new char[]{'a','b','c'};
		System.out.println(arr1);//abc
	}
}

02、方法的重写(override/overwrite)

1、Person类

package com.atguigu.java1;

public class Person {

	String name;
	int age;
	
	public Person(){
		
	}
	
	public Person(String name,int age){
		this.name = name;
		this.age = age;
	}
	
	public void eat(){
		System.out.println("吃饭");
	}
	
	private void show(){
		System.out.println("我是一个人。");
	}
	
	public void walk(int distance){
		System.out.println("走路,走的距离是:" + distance + "公里");
		show();	//是私有的,student不能重写,调用的仍然是父类中的
		eat();	//是公共的,student中重写了父类中的,故调用的是student中的方法。
	}
	
	public Object info(){
		return null;
	}
	
	public double info1(){
		return 1.0;
	}
}

2、Student类

package com.atguigu.java1;

public class Student extends Person{

	String major;
	
	public Student(){
		
	}
	
	public Student(String major){
		this.major = major;
	}
	
	public void study(){
		System.out.println("学习,专业是:" + major);
	}
	
	//对父类中的eat()进行了重写
	public void eat(){//左边有个小三角
		System.out.println("学生应该多吃有营养的。");
	}
	
	public void show(){//这不是重写,因为父类中是private,权限小,子类看不到
		System.out.println("我是一个学生。");
	}
	
	public String info(){//返回值可以是父类(object)返回值类型的子类
		return null;
	}
	
	//不是同一个类型,所以报错。
//	public int info1(){
//		return 1;
//	}
//	
	
	//实际开发中重写的方法:
	
	//方法1.可以直接将父类的方法的第一行粘过来,直接写方法体
//	public void walk(int distance){
//		System.out.println("重写的方法");
//	}
	
	//方法2.直接输入父类的方法名,Alt + /,选择即可生成
//	@Override//注解。
//	public void walk(int distance) {
//		System.out.println("重写的方法");
//	}
	//}
}

3、测试类

package com.atguigu.java1;

/*
 * 方法的重写(override/overwrite)
 * 
 * 1.重写:子类继承父类以后,可以对父类中同名同参的方法进行覆盖操作。
 * 2.应用:重写以后,当创建子类对象以后,通过子类对象去调用子父类中同名同参数方法时,实际执行的是子类重写的父类的方法。
 *   即在程序执行时,子类的方法将覆盖父类的方法。(子类会继承父类中的所有的方法,当父类中的方法不太适合子类的时候,子类就可以重写该方法)
 *   
 *   定义一个父类对象,通过父类对象调用同名同参方法,所调用的是父类的方法,与子类没关系。
 * 3.重写的规定:
 * 		方法的声明:权限修饰符 返回值类型 方法名(形参列表) throws 异常的类型{
 * 						//方法体
 * 				 }
 * 		约定俗称:子类中的叫重写的方法,父类中的叫被重写的方法。
 * 		① 子类重写的方法的方法名和形参列表必须和父类被重写的方法的方法名、形参列表相同; 
 * 		② 子类重写的方法使用的访问权限不能小于父类被重写的方法的访问权限,
 *   		特殊情况: 子类不能重写父类中声明为private权限的方法;	
 *   (学生对象调用父类中的walk方法,在父类中的walk方法中调用show和eat方法,父类中的show()是私有的,虽然子类中有同名方法,但不是重写,所调用的是父类中的方法
 *   父类中的eat方法是公共的,子类可以重写,所调用的是子类的eat方法)
 *   
 *   	③ 返回值类型:
 *   		> 父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void;
 *   		> 父类被重写的方法的返回值类型是A类型,则子类重写的方法的返回值类型可以是A类或A类的子类;
 *   		> 父类被重写的方法的返回值类型如果是基本数据类型(比如:double),则子类重写的方法的返回值类型必须是相同的基本数据类型(必须是:double)。
 *   		没有自动类型提升一回事。
 *   		
 *   	④ 子类重写的方法抛出的异常不能大于父类被重写的方法抛出的异常;(具体放到异常处理时候讲)
 * *************************************************************************************
 * 注意:子类与父类中同名同参数的方法必须同时声明为非static的(重写只考虑非static的),或者同时声明为static的(若父类中声明的是static方法,那么子类就不可以重写,静态的不叫重写)。
 * 		因为静态的方法不能被覆盖,是随着类的加载而加载的
 * 面试题:区分方法的重载与重写(有的书也叫做“覆盖”)
 * 		答:方法的重写Overriding和重载Overloading是Java多态性的不同表现。
 * 		重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。
 * 		如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。
 * 		子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被"屏蔽"了。
 * 		如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。
 * 
 */
public class PersonTest {

	public static void main(String[] args) {
		Student s = new Student("计算机科学与技术");
		s.eat();
		s.walk(10);

		System.out.println("************");
		s.study();

		Person p1 = new Person();
		p1.eat();
	}
}

2.1、方法的练习

1、练习1

1.如果现在父类的一个方法定义成private访问权限,在子类中将此方法声明为default访问权限,那么这样还叫重写吗?(NO)

2、练习2

/*
 * 2.修改练习1.2中定义的类Kids,在Kids中重新定义employeed()方法,
 * 	  覆盖父类ManKind中定义的employeed()方法,
 *   输出“Kids should study and no job.”
 */
public class Kids extends ManKind{

	private int yearsOld;	//年限
	
	public Kids() {

	}

	public Kids(int yearsOld) {
		this.yearsOld = yearsOld;
	}

	public int getYearsOld() {
		return yearsOld;
	}

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

	public void printAge(){
		System.out.println("I am " + yearsOld);
	}
	
	public void employeed(){
		System.out.println("Kids should study and no job.");
	}
}

MindKids类

public class ManKind {

	private int sex;	//性别
	private int salary;	//薪资
	
	public ManKind() {
		
	}

	public ManKind(int sex, int salary) {
		this.sex = sex;
		this.salary = salary;
	}

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

	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 class KidsTest {
	public static void main(String[] args) {
		
		Kids someKid = new Kids(12);
		
		someKid.printAge();
		
		someKid.setYearsOld(15);
		someKid.setSalary(0);
		someKid.setSex(1);
		
		someKid.employeed();
		someKid.manOrWoman();
	}
}

03、四种访问权限修饰符

四种权限修饰符
在这里插入图片描述
Order类

package com.atguigu.java2;
/*
 * 体会四种不同的权限修饰符
 * 
 * 
 */
public class Order {

	private int orderPrivate;
	int orderDefault;
	protected int orderProtected;
	public int orderPublic;
	
	private void methodPrivate(){
		orderPrivate = 1;
		orderDefault = 2;
		orderProtected = 3;
		orderPublic = 4;
	}
	
	void methodDefault(){
		orderPrivate = 1;
		orderDefault = 2;
		orderProtected = 3;
		orderPublic = 4;
	}
	
	protected void methodProtected(){
		orderPrivate = 1;
		orderDefault = 2;
		orderProtected = 3;
		orderPublic = 4;
	}
	
	public void methodPublic(){
		orderPrivate = 1;
		orderDefault = 2;
		orderProtected = 3;
		orderPublic = 4;
	}
}

Ordertest类

package com.atguigu.java2;

public class OrderTest {
	public static void main(String[] args) {
		
		Order order = new Order();
		
		order.orderDefault = 1;
		order.orderProtected = 2;
		order.orderPublic = 3;
		
		order.methodDefault();
		order.methodProtected();
		order.methodPublic();
		
		//同一个包中的其它类,不可以调用Order类中私有的属性
//		order.orderPrivate = 4;	//The field Order.orderPrivate is not visible
//		order.methoPrivate();
	}
}

SubOrder类

package com.atguigu.java3;

import com.atguigu.java2.Order;


public class SubOrder extends Order
{

	public void method()
	{
		orderProtected = 1;
		orderPublic = 2;
		
		methodProtected();
		methodPublic();
		
		//在不同包的子类中,不能调用Order类中声明为private和缺省的权限的属性、方法
//		orderDefault = 3;
//		orderPrivate = 4;
//		
//		methodDefault();
//		methodPrivate();
	}
}

OrderTest类

package com.atguigu.java3;

import com.atguigu.java2.Order;

public class OrderTest {
	public static void main(String[] args) {
		
		Order order = new Order();
		order.orderPublic = 1;
		order.methodPublic();
		
		//不同包下的普通类(非子类)要使用Order类,不可以调用声明为private、缺省、protected权限的属性、方法。
//		order.orderPrivate = 2;
//		order.orderProtected = 3;
//		order.orderProtected = 4;
//		
//		order.methodPrivate();
//		order.methodDefault();
//		order.methodProtected();
		
	}
	
	public void show(Order order){
		order.orderPublic = 1;
		order.methodPublic();
		
		//不同包下的普通类(非子类)要使用Order类,不可以调用声明为private、缺省、protected权限的属性、方法。
//		order.orderPrivate = 2;
//		order.orderProtected = 3;
//		order.orderProtected = 4;
		
//		order.methodPrivate();
//		order.methodDefault();
//		order.methodProtected();
	}
}

04、关键字:super

Person类

package com.atguigu.java3;

public class Person {

	String name;
	int age;
	int id = 1001;	
	//身份证号,子父类中出现了同名的属性了,对于属性来讲不会和方法一样存在覆盖之说,此时在内存中有两个id
	
	
	public Person(){
		System.out.println("我无处不在");
	}
	
	public Person(String name){
		this.name = name;
	}
	
	public Person(String name,int age){
		this(name);
		this.age = age;
	}
	
	public void eat(){
		System.out.println("人,吃饭");
	}
	
	public void walk(){
		System.out.println("人,走路");
	}
}

Student类

package com.atguigu.java3;

//子类创建的对象,堆空间中子类、父类的属性都有。

public class Student extends Person{
	
	String major;
	int id = 1002;	//学号
	
	public Student(){
//		有一个super();
	}
	
	public Student(String major){
		//有一个super()
		this.major = major;
	}
	
	public Student(String name,int age,String major){
//		this.age = age;
//		this.name = name;this.和set也可以给父类中的属性赋值。
		super(name,age);//子类的构造器中调用父类中对应的构造器
		this.major = major;
	}
	
	
	
	public void eat(){//重写
		System.out.println("学生多吃有营养的食物");
	}
	
	public void Study(){
		System.out.println("学生,学习知识。");
		this.eat();
		//如果,想调用父类中被重写的,不想调用子类中的方法,可以:
		super.eat();
		super.walk();//子父类中未重写的方法,用"this."或"super."调用都可以
	}
	public void show(){
		System.out.println("name = " + this.name + ",age = " + super.age);
		//this.name先在当前的student类中找是否有name这个属性,如果在自己这个类中没找到,就接着去父类中去找就找到了
		//super.age就没有在本类中找,直接到直接父类和间接父类中找。将本类中的age过掉了
		
		System.out.println("id = " + this.id);	//this可以省略
		System.out.println("id = " + super.id);//父类中的id
	}
}

测试类

package com.atguigu.java3;

/*
 * super关键字的使用
 * 1.super理解为:父类的
 * 2.super可以用来调用:属性、方法、构造器 
 * 
 * 3.super调用属性和方法
 * 		3.1 我们可以在子类的方法或构造器中,通过"super.属性"或"super.方法"的方式,显式的调用
 * 	父类中声明的属性或方法。但是,通常情况下,我们习惯省略这个"super."
 * 
 * 		3.2 对属性的特殊情况:当子类和父类中定义了同名的属性时,我们要想在子类中调用父类中声明的属性,则必须显式的 
 *  使用"super.属性"的方式,表明调用的是父类中声明的属性。(在子父类中一般都不定义同名的属性)
 *  	3.3 对方法的特殊情况:当子类重写了父类中的方法后,我们想在子类的方法中调用父类中被重写的方法时,必须显式的
 *  使用"super.方法"的方式,表明调用的是父类中被重写的方法。
 * 
 * 4.super调用构造器
 * 	  4.1  我们可以在子类的构造器中显式的使用"super(形参列表)"的方式,调用父类中声明的指定的构造器
 * 	  4.2 "super(形参列表)"的使用,必须声明在子类构造器的首行!this是调用本类中重载的其他的构造器,super是调用父类中重载的构造器
 *    4.3 我们在类的构造器中,针对于"this(形参列表)"或"super(形参列表)"只能二选一,不能同时出现。
 *    4.4 在构造器的首行,既没有显式的声明"this(形参列表)"或"super(形参列表)",则默认的调用的是父类中的空参构造器
 *    (即子类的每个构造器中如果没有this,那么都有一个默认的super().),
 *    见最后一行
 *    4.5 在类的多个构造器中,至少有一个类的构造器使用了"super(形参列表)",调用父类中的构造器。
 *    子类的构造器中,最多有n-1个this,至少有一个super
 *  //内存层面,在子类对象的堆空间中,一定会有父类中的属性,正是因为调用过super,将父类的结构加载到内存中
 *  
 *  
 *  		见package com.atguigu.exer1.Cylinder类中有例子
 */


public class SuperTest {
	public static void main(String[] args) {
		
		Student s = new Student();
		s.show();
		
		s.Study();
		
		Student s1 = new Student("Ton",21,"IT" );
		s1.show();
		
		System.out.println("***********************");
		Student s2 = new Student();//执行的是student这个类中的空参构造器,这个构造器中默认有一个super(),调用父类中的空参构造器。
		
	}
}

05、子类对象实例化过程

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

package com.atguigu.java3;

/*
 * 子类对象实例化的全过程
 * 
 * 1.从结果上看:
 * 		子类继承父类以后,就获取了父类中声明的属性或方法。
 * 		创建子类的对象中,在堆空间中,就会加载所有父类(直接父类、间接父类)中声明的属性。
 * 
 * 2.从过程上看:
 * 		当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用其父类构造器,
 * 		直到调用了java.lang.Object类中空参的构造器为止,正因为加载过所有父类的结构,所以才可以看到内存中有
 * 		父类的结构,子类对象可以考虑进行调用。
 * 
 * 明确:虽然创建子类对象时,调用了父类的构造器,但是自始至终就创建过一个对象,
 *      即为new的子类对象
 * 
 * 注:
 * (为什么说创建了一个子类对象,父类中的属性也会在堆中的该对象中体现:因为
 * 当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用其父类构造器,
 * 一调用父类构造器,父类中的结构就会加载过来)
 * 
 */
public class InstanceTest {

}

5.1、关于super的练习

Account类

package com.atguigu.exer2;
/*
 * 写一个名为Account的类模拟账户。该类的属性和方法如下图所示。
 * 该类包括的属性:账号id,余额balance,年利率annualInterestRate;
 * 包含的方法:访问器方法(getter和setter方法),
 * 返回月利率的方法getMonthlyInterest(),
 * 取款方法withdraw(),存款方法deposit()。
 * 
 */


public class Account {

	private int id;	//账号
	private double balance;	//余额
	private double annualInterestRate;	//年利率
	
	public Account(int id, double balance, double annualInterestRate) {
		super();//删不删都在
		this.id = id;
		this.balance = balance;
		this.annualInterestRate = annualInterestRate;
	}

	
	//方法
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public double getBalance() {
		return balance;
	}

	public void setBalance(double balance) {
		this.balance = balance;
	}

	public double getAnnualInterestRate() {
		return annualInterestRate;
	}

	public void setAnnualInterestRate(double annualInterestRate) {
		this.annualInterestRate = annualInterestRate;
	}
	
	
	
	
	//返回月利率的方法
	public double getMonthlyInterest(){	
		return annualInterestRate / 12;
	}
	
	//取款方法
	public void withdraw (double amount){	
		if(balance >= amount){
			balance -= amount;
			return;
		}
		System.out.println("余额不足");
	}
	
	//存款方法
	public void deposit (double amount){	
		if(amount > 0){
			balance += amount;
			
		}
	}
}

AccountTest类

package com.atguigu.exer2;
/*
 * 写一个用户程序测试Account类。在用户程序中,
 * 创建一个账号为1122、余额为20000、年利率4.5%的Account对象。
 * 使用withdraw方法提款30000元,并打印余额。再使用withdraw方法提款2500元,
 * 使用deposit方法存款3000元,然后打印余额和月利率。
 */
public class AccountTest {
	public static void main(String[] args) {
		Account acct=new Account(1122, 20000, 0.045);
		
		acct.withdraw(30000);
		System.out.println("您的账户余额为: "+acct.getBalance());
		
		acct.withdraw(2500);
		System.out.println("您的账户余额为: "+acct.getBalance());
		acct.deposit(3000);
		System.out.println("您的账户余额为: "+acct.getBalance());

		System.out.println("月利率为: "+(acct.getMonthlyInterest()*100)+"%");
	}

}

CheckAccount类

package com.atguigu.exer2;

/*
 * 创建Account类的一个子类CheckAccount代表可透支的账户,该账户中定义一个属性overdraft代表可透支限额。
 * 在CheckAccount类中重写withdraw方法,其算法如下:
 * 如果(取款金额<账户余额),
 * 可直接取款
 * 如果(取款金额>账户余额),
 * 计算需要透支的额度
 * 判断可透支额overdraft是否足够支付本次透支需要,如果可以
 * 		将账户余额修改为0,冲减可透支金额
 * 如果不可以
 * 		提示用户超过可透支额的限额
 * 
 */
public class CheckAccount extends Account{
	//错误提示:Implicit super constructor Account() is undefined for default constructor. Must define an explicit constructor
	//方法1在父类中提供一个空参构造器,方法2调用父类中指定的构造器
	
	private double overdraft;//可透支限额
	
	public CheckAccount(int id,double balance,double annualInterestRate,double overdraft)
	{
		super(id, balance, annualInterestRate);
		this.overdraft=overdraft;
	}
	
	public double getOverdraft() {
		return overdraft;
	}

	public void setOverdraft(double overdraft) {
		this.overdraft = overdraft;
	}

	@Override
	public void withdraw(double amount) {
		if(getBalance()>amount)//余额足够
		{
			//方式1
			//setBalance(getBalance()-amount);
			//方式2
			super.withdraw(amount);
		}else if(overdraft>=(amount-getBalance()))//透支额度+余额足够消费
		{
			
				overdraft-=(amount-getBalance());
				setBalance(0);//或super.withdraw(getBalance());
		}else//超过可透支限额
		{
			System.out.println("超过可透支限额");
			
		}
		
	
		
	}
	
}

CheckAccountTest类

package com.atguigu.exer2;

/*
 * 写一个用户程序测试CheckAccount类。在用户程序中,
 * 创建一个账号为1122、余额为20000、年利率4.5%,
 * 可透支限额为5000元的CheckAccount对象。
 * 使用withdraw方法提款5000元,并打印账户余额和可透支额。
 * 再使用withdraw方法提款18000元,并打印账户余额和可透支额。
 * 再使用withdraw方法提款3000元,并打印账户余额和可透支额。
 * 
 */
public class CheckAccountTest {
	public static void main(String[] args) {
		CheckAccount acct=new CheckAccount(1122, 20000, 0.045, 5000);
		
		acct.withdraw(5000);
		System.out.println("您的账户额为: "+acct.getBalance());
		System.out.println("您的可透支额度为:"+acct.getOverdraft());
		acct.withdraw(18000);
		System.out.println("您的账户额为: "+acct.getBalance());
		System.out.println("您的可透支额度为:"+acct.getOverdraft());
		acct.withdraw(3000);
		System.out.println("您的账户额为: "+acct.getBalance());
		System.out.println("您的可透支额度为:"+acct.getOverdraft());

	}
}

06、面向对象特征之三:多态性

Person类

package com.atguigu.java4;

public class Person {
	String name;
	int age;
	int id=1001;
	
	public void eat(){
		System.out.println("人,吃饭");
	}
	
	public void walk(){
		System.out.println("人,走路");
	}
	
}

Woman类

package com.atguigu.java4;

public class Woman extends Person{

	boolean isBeauty;
	
	public void goShopping(){
		System.out.println("女人喜欢购物");
	}
	
	public void eat(){//重写
		System.out.println("女人少吃,为了减肥。");
	}
	
	public void walk(){//重写
		System.out.println("女人,窈窕的走路。");
	}
}

Man类

package com.atguigu.java4;

public class Man extends Person{
	
	boolean isSmoking;
	
	int id=1002;
	
	public void earnMoney(){
		System.out.println("男人负责工作养家");
	}
	
	public void eat() {//重写父类
		System.out.println("男人多吃肉,长肌肉");
	}
	
	public void walk() {//重写
		System.out.println("男人霸气的走路");
	}
}

测试类

package com.atguigu.java4;

/*
 * 面向对象之三:多态性
 * 
 * 1.理解多态性:可以理解为一个事物的多种形态。
 * 2.何为多态性:
 * 	 对象的多态性:父类的引用指向子类的对象(或子类的对象赋值给父类的引用)
 * 
 * 3.多态的使用:虚拟方法调用
 * 当我们通过变量名去调用子父类中同名同参的方法时,编译时我们认为是调用的父类中声明的方法,解释运行时,实际执行的是子类重写的方法。
 * 	或者说有了对象多态性以后,我们在编译期,只能调用父类中所声明的方法(若子类中有,父类中没有的方法是编译不了的),但在执行期实际执行的是子类重写父类的方法
 * 			简称:编译时,看左边;运行时,看右边。
 *  
 *  若编译时类型和运行时类型不一致,就出现了对象的多态性(Polymorphism)
 *  多态情况下,
 *  	“看左边”:看的是父类的引用(父类中不具备子类特有的方法)
 *  	“看右边”:看的是子类的对象(实际运行的是子类重写父类的方法)
 *  
 *  4.多态性的使用前提:
 *  	① 要有类的继承关系
 *  	② 要有子类中方法的重写
 *  5.对象的多态性:只适用于方法,不适用于属性(对于属性:编译和运行都看左边)
 *  
 * 注:
 * 1.虽然创建子类对象时,调用了父类的构造器,但自始至终就创建过一个对象,即为new的子类对象。(加载进来的父类属性不对外暴露具体地址,对外只暴露所创建对象的这一个地址)
 * 2.为什么super()或this调用语句只能作为构造器中的第一句出现?
 * 答:无论通过哪个构造器创建子类对象,需要保证先初始化父类。当子类继承父类后,“继承”父类中所有的属性和方法,因此子类有必要知道父类如何为对象进行初始化。

 */
public class PersonTest {
	public static void main(String[] args) {
		
	Person p1 = new Person();
	p1.eat();
	
	Man man = new Man();
	man.eat();
	man.age = 25;
	man.earnMoney();
	
	//************************************
	//对象的多态性,父类的引用指向子类的对象
	Person p2 = new Man();//此时,栈空间中有p2,堆空间中有Person类中的name,age,id和Man类中的id和isSmoking,
	//对于属性来说,p2只能调用父类中的属性,即看左不看右
//	Person p3 = new Woman();
	
	//多态的使用:当调用子父类同名同参数方法时,实际调用的是子类重写父类的方法---虚拟方法调用
	p2.eat();
	p2.walk();
	
	//p2.earnMoney();    
	//报错:The method earnMoney() is undefined for the type Person(person)类中没定义过。
	//即p2能调用的是Person中有的方法
	
	System.out.println(p2.id);//1001	对象的多态性:只适用于方法,不适用于属性(编译和运行都看左边)
	
	}
}

6.0、虚拟方法调用(Virtual Method Invocation)

  • 正常的方法调用
Person e = new Person();
e.getInfo();
Student e = new Student();
e.getInfo();
  • 虚拟方法调用(多态情况下)
    子类中定义了与父类同名同参数的方法,在多态情况下,将此时父类的方法称为虚拟方法,父类根据赋给它的不同子类对象,动态调用属于子类的该方法。这样的方法调用在编译期是无法确定的。
Person e = new Student();
e.getInfo(); //调用Student类的getInfo()方法
  • 编译时类型和运行时类型
    编译时e为Person类型,而方法的调用是在运行时确定的,所以调用的是Student类
    的getInfo()方法。——动态绑定

举例

package com.atguigu.java4;

/*
 * 多态性应用举例
 */
public class AnimalTest {
	
	public static void main(String[] args) {
		AnimalTest test = new AnimalTest();
		test.func(new Dog());
		
		test.func(new Cat());
	}

	public void func(Animal animal){	//Animal animal = new Dog();
		//声明一个类型,拿子类的对象去赋值,就是多态性的一个应用场景
		animal.eat();
		animal.shout();
		if(animal instanceof Dog)//判断是否可以向下转型,
		{
			Dog d=(Dog)animal;//向下转型
			d.watchDoor();//使用Dog中特有的方法
		}
	}
	
	//如果没有多态性,就会写很多如下的方法,去调用
	/*
	 * public void func(Dog dog){ dog.eat(); dog.shout(); }
	 * 
	 * public void func(Cat cat){ cat.eat(); cat.shout(); }
	 */
}

//父类
class Animal{
	
	public void eat(){
		System.out.println("动物,进食");
	}
	
	public void shout(){
		System.out.println("动物:叫");
	}
}

//继承
class Dog extends Animal{
	public void eat(){//重写方法
		System.out.println("狗吃骨头");
	}
	
	public void shout() {//重写方法
		System.out.println("汪!汪!汪!");
	}
	public void watchDoor()
	{
		System.out.println("看门");
	}
}

//继承
class Cat extends Animal{
	public void eat(){
		System.out.println("猫吃鱼");
	}
	
	public void shout() {
		System.out.println("喵!喵!喵!");
	}
}

//举例2

class Order{
	
}





6.0.1 、复习

  • 子类能否获取父类中private权限的属性或方法?
    可以的,对于父类中私有的属性,提供get(),set()方法,子类照样可以修改;对于父类中私有的方法,放入到公共的方法中是一样可以调用的

6.1、虚拟方法的补充

package com.atguigu.java5;

import java.util.Random;
/*
 *  方法的重载与重写区别
 * 
 * 1.二者的定义细节:略
 * 2.从编译和运行的角度看:
 * 重载,是指允许存在多个同名方法,而这些方法的参数不同。
 * 编译器根据方法不同的参数表,对同名方法的名称做修饰。
 * 对于编译器而言,这些同名方法就成了不同的方法。
 * 它们的调用地址在编译期就绑定了。Java的重载是可以包括父类和子类的,
 * 即子类可以重载父类的同名不同参数的方法。所以:对于重载而言,在方法调用之前,
 * 编译器就已经确定了所要调用的方法,这称为“早绑定”或“静态绑定”;
 * 
 * 而对于多态,只有等到方法调用的那一刻,解释运行器才会确定所要调用的具体方法,
 * 这称为“晚绑定”或“动态绑定”。  
 * 3.重载: 不表现为多态性
 * 	 重写: 表现为多态性
 * 
 * 引用一句Bruce Eckel的话:“不要犯傻,如果它不是晚绑定,它就不是多态。”
 */
//面试题:多态是编译时行为还是运行时行为?答:运行时行为
//证明如下:

class Animal  {
 
	protected void eat() {
		System.out.println("animal eat food");
	}
}

class Cat  extends Animal  {
 
	protected void eat() {
		System.out.println("cat eat fish");
	}
}

class Dog  extends Animal  {
 
	public void eat() {
		System.out.println("Dog eat bone");

	}

}

class Sheep  extends Animal  {
 
	public void eat() {
		System.out.println("Sheep eat grass");

	}
 
}

public class InterviewTest {

	public static Animal  getInstance(int key) {
		switch (key) {
		case 0:
			return new Cat ();
		case 1:
			return new Dog ();
		default:
			return new Sheep ();
		}

	}

	public static void main(String[] args) {
		int key = new Random().nextInt(3);

		System.out.println(key);

		Animal  animal = getInstance(key);//只有在运行时才知道真正new的是谁,因此是运行时行为。
		
		animal.eat();
		 
	}

}

6.2、向下转型的使用

Person 类

package com.atguigu.java;

public class Person {
	String name;
	int age;
	int id=0;
	
	public void eat(){
		System.out.println("人,吃饭");
	}
	
	public void walk(){
		System.out.println("人,走路");
	}
	
}

Man 类

package com.atguigu.java;

public class Man extends Person{
	
	boolean isSmoking;
	int id=2;
	
	public void earnMoney(){
		System.out.println("男人负责工作养家");
	}
	
	public void eat() {
		System.out.println("男人多吃肉,长肌肉");
	}
	
	public void walk() {
		System.out.println("男人霸气的走路");
	}
}



Woman 类

package com.atguigu.java;

public class Woman extends Person{

	boolean isBeauty;
	
	public void goShopping(){
		System.out.println("女人喜欢购物");
	}
	
	public void eat(){
		System.out.println("女人少吃,为了减肥。");
	}
	
	public void walk(){
		System.out.println("女人,窈窕的走路。");
	}
}

PersonTest 类

package com.atguigu.java;



/*
 * 面向对象之三:多态性
 * 
 * 1.理解多态性:可以理解为一个事物的多种形态。
 * 2.何为多态性:
 * 	 对象的多态性:父类的引用指向子类的对象(或子类的对象赋值给父类的引用)
 * 
 * 3.多态的使用:虚拟方法调用
 * 当我们通过变量名去调用子父类中同名同参的方法时,编译时我们认为是调用的父类中声明的方法,解释运行时,实际执行的是子类重写的方法。
 * 	或者说有了对象多态性以后,我们在编译期,只能调用父类中所声明的方法(若子类中有,父类中没有的方法是编译不了的),但在执行期实际执行的是子类重写父类的方法
 * 			简称:编译时,看左边;运行时,看右边。
 *  
 *  若编译时类型和运行时类型不一致,就出现了对象的多态性(Polymorphism)
 *  多态情况下,
 *  	“看左边”:看的是父类的引用(父类中不具备子类特有的方法)
 *  	“看右边”:看的是子类的对象(实际运行的是子类重写父类的方法)
 *  
 *  4.多态性的使用前提:
 *  	① 要有类的继承关系
 *  	② 要有子类中方法的重写
 *  5.对象的多态性:只适用于方法,不适用于属性(对于属性:编译和运行都看左边)
 *  *****************************************************
 *  6.instanceof关键字的使用
	 
	   
	 
	  a instanceof A:
	  ① 判断对象a是否是类A的实例。如果是,返回true,如果不是,返回false;
	 
	  使用情境:为了避免在向下转型时出现ClassCastException异常,我们在进行向下转型之前,先进行
	  instanceof的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型。
	  
	  ② 如果a instanceof A返回true,则a instanceof B也返回true。 其中类B是类A的父类。
	  
	  
	  这里a是个变量(引用),A是个类型
	  
	  
	  注:作用是测试它左边的对象是否是它右边的类的实例,返回 boolean 的数据类型;
*/

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

		Person p1 = new Person();
		p1.eat();

		Man man = new Man();
		man.eat();
		man.age = 25;
		man.earnMoney();

		
		
		
		
		
		
		
		
		
		
		
		// ************************************
		// 对象的多态性,父类的引用指向子类的对象
		Person p2 = new Man();
//	此时,栈空间中有p2,堆空间中有Person类中的name,age,id和Man类中的id和isSmoking,
//	由于对象是Person类型的,只能调用Person中声明的结构(属性和方法),而Man中结构(属性和结构),相当于被屏蔽掉了
//  没法调用了

//		 对于属性来说,p2只能调用父类中的属性,即看左不看右
//	Person p3 = new Woman();

		// 多态的使用:当调用子父类同名同参数方法时,实际调用的是子类重写父类的方法---虚拟方法调用
		p2.eat();
		p2.walk();

		// p2.earnMoney();
		// 报错:The method earnMoney() is undefined for the type Person(person)类中没定义过。
		// 即p2能调用的是Person中有的方法

		System.out.println(p2.id);// 1001 对象的多态性:只适用于方法,不适用于属性(编译和运行都看左边)

		
		
		
		
		
		
		
		System.out.println("**************************************************");
		// 不能调用子类所特有的方法、属性:编译时,p2是Person类型。
//	p2.earnMoney();
//	p2.isSmoking=true;
		p2.name = "Tom";// 可以调用Person类中的属性。
		// 有了对象的多态性以后,内存中实际上加载了子类特有的属性和方法的,但是由于变量声明为父类类型,导致
		// 编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。

		
		
		
		
//		对于编译器而言,看到的p2不再是Person类型的才可以,因为编译就是看左边,要想调用子类
//		所特有的,那只能将Person类型给改了,即将其声明成Man类型。
	
		
//		 如何才能调用子类特有的属性和方法?
		// 向下转型:使用强制类型转换符。
		Man m1 = (Man) p2;
		m1.earnMoney();
		m1.isSmoking = true;

		
		
		
		
		
//		 使用强转时,可能出现ClassCastException的异常
//	Woman w1=(Woman)p2;//p2是Man的实例,与Woman无关
//	w1.goShopping();
		

		if (p2 instanceof Woman) {
			Woman w1 = (Woman) p2;
			w1.goShopping();
			System.out.println("**********Woman*********");
		}

		if (p2 instanceof Man) {
			Man m2 = (Man) p2;
			m2.earnMoney();
			System.out.println("*********Man************");
		}

		if (p2 instanceof Person) {//Person是Man的父类
			System.out.println("***********Person************");
		}

		if (p2 instanceof Object) {
			System.out.println("***********object************");
		}

		
		
		
//		   由下可知,要想向下转型成功,如下
//		Person p1=new Woman(); Woman w1=(Woman)p1;
//		Object obj=new Woman(); Person pp=(Person)obj; 
	
		
		
// 向下转型的常见问题
//		 练习
//		 问题1:编译时通过,运行时不通过
//		 举例一
//			Person p3 = new Woman();
//			Man m3 = (Man)p3;

		
//		 举例二  new的Person中没有子类的功能,因此强转失败。
//		Person p4 = new Person();
//		Man m4 = (Man) p4;

		
		
		
		
//		 问题二:编译通过,运行时也通过,正确的写法
//		Object obj = new Woman();// new了一个Woman,向上转型为(或多态性)Object,即obj是Object类型
//		 可以向下转型为Woman的父类Person类型
//		Person p = (Person) obj;

		
		
		
//		 问题三:编译不通过
//		 不相关的两个类是不可以赋值的
//			Man m5 = new woman();

//			String str = new Date();

//			Object o = new Date();
//			String str1 = (String)o;
	}

}



  • 地址值包括两部分,如下。因为有类型的限制,p2如果直接赋值给m1是不行的,加上强制类型转换符后就可以了
    强制类型转换后,类型才是Man就可以调用其特有的结构了.

在这里插入图片描述

在这里插入图片描述

6.3、多态性的练习

1、练习1

package com.atguigu.exer;

/*
 * 练习:子类继承父类
 * 
 * 1.若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类里的同名方法,
 * 系统将不可能把父类里的方法转移到子类中。即编译看左边,运行看右边
 * 
 * 2.对于属性则不存在这样的现象,即使子类里定义了与父类完全相同的实例变量,
 * 这个实例变量依然不可能覆盖父类中定义的实例变量(调用的是谁就看声明的是谁)。
 * 即编译运行都看左边
 * 如
 * 	例1	
 * 		Sub s= new Sub();
		System.out.println(s.count);
	此时s是Sub类中的
	例2
		Base b = s;
		System.out.println(b.count);
 * 
 */
class Base {
	int count= 10;
	public void display() {
		System.out.println(this.count);
	}
}


class Sub extends Base {
	int count= 20;
	public void display() {
		System.out.println(this.count);
	}
}


public class FieldMethodTest {
	public static void main(String[] args){
		Sub s= new Sub();
		System.out.println(s.count);	//20,就近原则,先在Sub中找
		s.display();//20
		
		Base b = s;
		//==:对于引用数据类型来讲,比较的是两个引用数据类型变量的地址值是否一样。
		System.out.println(b == s);	//true,赋值的就是地址值。
		System.out.println(b.count);	//10多态性不适用于属性
		b.display();//20
	}
}

2、练习2

package com.atguigu.exer;

/*
 *  * 建立InstanceTest类,在类中定义方法method(Person e);
 * 
 * 在method中:
 * (1)根据e的类型调用相应类的getInfo()方法。
 * (2)根据e的类型执行:
 * 		如果e为Person类的对象,输出:
 * 		“a person”;
 * 
 * 		如果e为Student类的对象,输出:
 * 		“a student”
 * 		“a person ”
 * 
 * 		如果e为Graduate类的对象,输出:
 * 		“a graduated student”
 * 		“a student”
 * 		“a person”
 * 
 */


public class InstanceTest
{

	public static void main(String[] args) {
		InstanceTest test=new InstanceTest();
		test.method(new Student());
	}
	
	public void method(Person e)
	{
		//虚拟方法调用
		String info=e.getInfo();
		System.out.println(info);
		/*
		if(e instanceof Graduate)
		{
			System.out.println("a graduated student");
			System.out.println("a student");
			System.out.println("a person");
		}else if(e instanceof Student)
		{
			System.out.println("a student");
			System.out.println("a person");
		}
		else
		{
			System.out.println("a person");
		}
		*/
		
		if(e instanceof Graduate)
			System.out.println("a graduated student");
		if(e instanceof Student)
			System.out.println("a student");
		if(e instanceof Person)
			System.out.println("a person");
	}
}





class Person {
	protected String name = "person";
	protected int age = 50;

	public String getInfo() {
		return "Name: " + name + "\n" + "age: " + age;
	}
}



class Student extends Person {
	protected String school = "pku";

	public String getInfo() {
		return "Name: " + name + "\nage: " + age + "\nschool: " + school;
	}
}



class Graduate extends Student {
	public String major = "IT";

	public String getInfo() {
		return "Name: " + name + "\nage: " + age + "\nschool: " + school + "\nmajor:" + major;
	}
}


3、练习3
在这里插入图片描述

GeometricObject类

package com.atguigu.exer1;


//见日记13.3
public class GeometricObject {
	
	protected String color;
	protected double weight;
	
	
	public GeometricObject(String color, double weight) {
		super();
		this.color = color;
		this.weight = weight;
	}
	
	
	
	
	
	
	
	public String getColor() {
		return color;
	}
	public void setColor(String color) {
		this.color = color;
	}
	public double getWeight() {
		return weight;
	}
	public void setWeight(double weight) {
		this.weight = weight;
	}
	
	public double findArea()
	{
		return 0.0;
	}
}

Circle类

package com.atguigu.exer1;


//当定义好该行时,马上报错,是因为父类中没有提供空参构造器,而子类的空参构造器中的super()默认
//调用了父类的空参构造器,即使不调用父类的空参构造器,调用父类的某一个有参构造器也行,如下:
public class Circle extends GeometricObject {

	private double radius;
	
	public Circle(double radius,String color, double weight) {
		super(color, weight);
		this.radius=radius;
		
	}

	public double getRadius() {
		return radius;
	}

	public void setRadius(double radius) {
		this.radius = radius;
	}
	
	public double findArea()
	{
		return 3.14*radius*radius;
	}

	
}

MyRectangle类

package com.atguigu.exer1;

//一开始还是会有构造器出错问题,同上
public class MyRectangle extends GeometricObject {

	
	double width;
	double height;
	
	public MyRectangle(double width,double height,String color, double weight) {
		super(color, weight);
		this.width=width;
		this.height=height;
	}

	public double getWidth() {
		return width;
	}

	public void setWidth(double width) {
		this.width = width;
	}

	public double getHeight() {
		return height;
	}

	public void setHeight(double height) {
		this.height = height;
	}

	@Override
	public double findArea() {
		return width*height;
	}
}

GeometricTest类

package com.atguigu.exer1;

/*
 * 定义一个测试类GeometricTest,编写equalsArea方法测试两个对象的面积是否相等
 * (注意方法的参数类型,利用动态绑定技术),
 * 编写displayGeometricObject方法显示对象的面积(注意方法的参数类型,利用动态绑定技术)。
 * 
 */
public class GeometricTest {

	
	
	public static void main(String[] args) {
		GeometricTest test=new GeometricTest();
		
		Circle c1=new Circle(2.3, "white", 1.0);
		test.displayGeometricObject(c1);
		Circle c2=new Circle(3.3, "white", 1.0);
		test.displayGeometricObject(c2);
		
		boolean isEquals=test.equalsArea(c1, c2);
		System.out.println("c1和c2的面积是否相等:"+isEquals);
		
		MyRectangle rect=new MyRectangle(2.1, 3.4, "red", 2.0);
		test.displayGeometricObject(rect);
		
	}
	public void displayGeometricObject(GeometricObject o)//GeometricObject o=new Circle(……);
	{
		System.out.println("面积为: "+o.findArea());
	}
	public boolean equalsArea(GeometricObject o1,GeometricObject o2)
	{
		return o1.findArea()==o2.findArea();
	}
}

练习4

/*
 * 面试题:多态是编译时行为还是运行时行为?如何证明?
 * 
 * 证明见如下:
 */
import java.util.Random;

class Animal  {

	protected void eat() {
		System.out.println("animal eat food");
	}
}

class Cat  extends Animal  {

	protected void eat() {
		System.out.println("cat eat fish");
	}
}

class Dog  extends Animal  {

	public void eat() {
		System.out.println("Dog eat bone");
	}
}

class Sheep  extends Animal  {

	public void eat() {
		System.out.println("Sheep eat grass");

	}

}

public class InterviewTest {

	public static Animal  getInstance(int key) {
		switch (key) {
		case 0:
			return new Cat ();
		case 1:
			return new Dog ();
		default:
			return new Sheep ();
		}

	}

	public static void main(String[] args) {
		int key = new Random().nextInt(3);

		System.out.println(key);

		Animal  animal = getInstance(key);
		
		animal.eat();
		 
	}
}

4、面试题拓展

package com.atguigu.exer;

/* 考查多态的笔试题目:
 * 面试题:多态是编译时行为还是运行时行为?如何证明?
 * 
 * 拓展问题
 */
public class InterviewTest1 {

	public static void main(String[] args) {
		Base1 base = new Sub1();
		base.add(1, 2, 3);//sub_1,调用子类重写的方法

		Sub1 s = (Sub1)base;
		s.add(1,2,3);//sub_2;有确定三个的优先调用
	}
}

class Base1 {
	public void add(int a, int... arr) {
		System.out.println("base1");
	}
}

//认为形参int...arr与形参int[] arr一样,故是重写
class Sub1 extends Base1 {

	public void add(int a, int[] arr) {
		System.out.println("sub_1");
	}

	//不是重写,用于混淆
	public void add(int a, int b, int c) {
		System.out.println("sub_2");
	}
	

}

07、Object 类的使用

package com.atguigu.java1;

/*
 * java.lang.Object类
 * 1.Object类是所有Java类的根父类;
 * 2.如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object类
 * 3.Object类中的功能(属性、方法)就具有通用性。
 * 
 * 属性:无,没有属性,都是方法
 * 方法:equals() / toString() / getClass() / hashCode() / clone() /finalize()
 * 	 wait() 、notify()、notifyAll()
 * 
 * 4.Object类只声明了一个空参的构造器。意味着造的所有其它类的对象,最终都会调用到Object空参构造器,因为每个类都会有super(形参列表)。
 * 面试题:
 * final、finally、finalize的区别?
 * final、finally这俩以后讲
 * finalize:对象在被回收之前,会调用当前对象的finalize()方法,不要主动的调用这个方法,有垃圾回收器自动调用
 * 即如果这个对象发现堆空间中的实体没有栈中的引用指向它了,此时对象就会调用该方法,将堆空间中的实体进行回收
 * 
 */
public class ObjectTest {

	public static void main(String[] args) {
		Order order=new Order();
		System.out.println(order.getClass().getSuperclass());
		//获取order所属类即Order,然后获取Order的父类
	}
}

class Order{//或者ctrl+t
	
}

7.1、Object类中的主要结构

在这里插入图片描述

7.2、==操作符与equals方法

	package com.atguigu.java1;

import java.sql.Date;

/*
 * 面试题: ==和equals的区别
 * 
 * 一、回顾==的使用
 * == : 运算符
 * 1.可以使用在基本数据类型变量和引用数据类型变量中
 * 2.如果比较的是基本数据类型变量:比较两个变量保存的数据是否相等。(不一定类型要相同)
 * 	 如果比较的是引用数据类型变量:比较两个对象的地址值是否相同,即两个引用是否指向同一个对象实体
 *  补充: == 符号使用时,必须保证符号左右两边的变量类型可以统一(原本相同或自动类型提升后相同)。 
 *  除了Boolean类型,其他七种类型都可以用==进行比较,true还是false与类型没有关系,看真实存储的值
 *  再如:System.out.println("hello" == new java.util.Date()); //编译不通过,因为类型不能够统一
 *
 * 二、equals()方法的使用
 * 1.是一个方法,而非运算符
 * 2.只能适用于引用数据类型。
 * 3.Object类中equals()的定义:
 * 		即自己定义的类进行比较
 * 		public boolean equals(Object obj){
 * 			return (this == obj);
 * 		}
 * 说明:Object类中系统自定义的equals()和==的作用是相同的,比较两个对象的地址值是否相同,即两个引用是否指向同一个对象实体。
 * 
 * 4.像String、Date、File、包装类    等都重写了Object类中的equals()方法.重写后,比较的不是
 * 	 两个引用的地址是否相同,而是比较两个对象的“实体内容”是否相同。(即内部属性是否相同)
 * 
 * 5.通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的"实体内容"(即我们比较关心的属性)是否相同。
 * 	   一般情况下,我们需要对Object类中的equals()进行重写。
 * 
 * 重写的原则:比较两个对象的实体内容是否相同。
 * 
 */
/*
 * 	int it = 65;
    float fl= 65.0f;
	System.out.println("65和65.0f是否相等?" + (it == fl)); //true
	char ch1 = 'A'; 
	char ch2 = 12;
	System.out.println("65和'A'是否相等?" + (it == ch1));//true
	System.out.println("12和ch2是否相等?" + (12 == ch2));//true 
	String str1 = new String("hello");
	String str2 = new String("hello");
	System.out.println("str1和str2是否相等?"+ (str1 == str2));//false
	System.out.println("str1是否equals str2?"+(str1.equals(str2)));//true
	System.out.println("hello" == new java.util.Date()); //编译不通过

 */
public class EqualsTest {
	public static void main(String[] args) {
		
		//基本数据类型
		int i = 10;
		int j = 10;
		double d = 10.0;
		System.out.println(i == j);	//true
		System.out.println(i == d); //true
		
//		boolean b =true;//Boolean不可以和另外七种基本数据类型进行比较
//		System.out.println(i == b);
		
		char c = 10;//见日记4,这个10就是整数10,即ascII码的10,
		System.out.println(i == c); //true
		
		char c1 = 'A';
		char c2 = 65;
		System.out.println(c1 == c2); //true,转化为整形
		//除了boolean类型,其他的类型都可以用==去比较,true还是false与类型没有关系,看真实存储的值。
		
		
		
		
		
		
		
		//引用数据类型
		Customer cust1 = new Customer("Tom" ,21);
		Customer cust2 = new Customer("Tom" ,21);
		System.out.println(cust1 == cust2); //false
		
		String str1 = new String("BAT");
		String str2 = new String("BAT");
		System.out.println(str1 == str2); //false
		System.out.println("*************************");
		System.out.println(cust1.equals(cust2));	//false(重写false后就是ture)   equals(Object obj)这里用到了多态
		System.out.println(str1.equals(str2));	//true(本身系统就重写了String类型的equals())
		
		Date date1 = new Date(23432525324L);
		Date date2 = new Date(23432525324L);
		System.out.println(date1.equals(date2));	//true
	}
}

Customer类

package com.atguigu.java1;

import java.util.Objects;

public class Customer {

	private String name;
	private int 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 Customer(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	public Customer() {
		super();
	}

	
	
	
	
	
	
	//自动生成的,即实际开发中我们都不是手写的,都是调用的
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Customer other = (Customer) obj;
		return age == other.age && Objects.equals(name, other.name);
	}

	
	
	//手动实现equals()
//	为每个类重写equals(),原则:比较两个对象的实体内容(即,name和age)是否相同
//	@Override
//	public boolean equals(Object obj) {
//		
//		System.out.println("Customer equals…………");
//		  if (this == obj) {//如果二者的引用地址相同,就返回true
//	            return true;
//	        }
//		  if(obj instanceof Customer)
//		  {
//			  Customer cust=(Customer)obj;
//			  //比较两个对象的两个属性是否都相同

//			  return this.age==cust.age&&this.name.equals(cust.name);
//		  }
//		  return false;
//	}
	

	
	
	
	
	
	
	
	//手动实现重写toString类
//	@Override
//	public String toString() {
//		return "Custmoer[name = "+name+",age= "+age+"]";
//	}
	//自动实现
	@Override
	public String toString() {
		return "Customer [name=" + name + ", age=" + age + "]";
	}
	
	

	
}

7.2.1、重写equals()方法的原则

  • 对称性:如果x.equals(y)返回是“true”,那么y.equals(x)也应该返回是“true”。
  • 自反性:x.equals(x)必须返回是“true”。
  • 传递性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那么z.equals(x)也应该返回是“true”。
  • 一致性:如果x.equals(y)返回是“true”,只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是“true”。
  • 任何情况下,x.equals(null),永远返回是“false”;x.equals(和x不同类型的对象)永远返回是“false”。
	int it = 65;
    float fl= 65.0f;
	System.out.println("65和65.0f是否相等?" + (it == fl)); //true
	char ch1 = 'A'; 
	char ch2 = 12;
	System.out.println("65和'A'是否相等?" + (it == ch1));//true
	System.out.println("12和ch2是否相等?" + (12 == ch2));//true 
	String str1 = new String("hello");
	String str2 = new String("hello");
	System.out.println("str1和str2是否相等?"+ (str1 == str2));//false
	System.out.println("str1是否equals str2?"+(str1.equals(str2)));//true
	System.out.println("hello" == new java.util.Date()); //编译不通过

练习一

package com.atguigu.exer2;
/*
 * 编写Order类,有int型的orderId,String型的orderName,
 * 相应的getter()和setter()方法,两个参数的构造器,重写父类的equals()方法:
 * public booleanequals(Object obj),
 * 并判断测试类中创建的两个对象是否相等。
 * 
 * 总结:
 * 1.String s1="BB";
 * 	 String s2="BB";
 *   s1==s2  true;//s1和s2指向常量池中的同一个“BB”,因此地址相同。
 * 2.String s1="BB";
 * 	 String s2="BB";
 * 	 s1.equals(s2);		true//对于String类型的equals()方法。比较的是属性的值是否相等
 * 3.String s1=new String("BB");
 * 	 String s2=new String("BB");
 * 	 s1==s2		false//s1和s2指向的是堆空间中两个不同的地址。
 * 4.String s1=new String("BB");
 *   String s2=new String("BB");
 *   s1.equals(s2);		true//对于String类型的equals()方法。比较的是属性的值是否相等
 */
public class OrderTest {

	public static void main(String[] args) {
		Order order1=new Order(1001,"AA");
		Order order2=new Order(1001,"BB");
//		Order order2=new Order(1001,new String("BB"));//另一种定义字符串的形式
		System.out.println(order1.equals(order2));
		
		Order order3=new Order(1001,"BB");
		System.out.println(order2.equals(order3));//true
		
		String s1="BB";
		String s2="BB";
		System.out.println(s1==s2);//true;
		
	}
	//String 中的内容存在于方法区里的常量池中,常量池中有个BB了,有栈空间中的s1指向它,常量池有个特点,若再定义的变量和已有的变量相同了
//	直接就复用了,即s2也指向BB了,意味着s1和s2付过来的地址是一样的,再以判断二者就是个true.
	
	
}

class Order
{
	private int orderId;
	private String orderName;
	
	
	public Order(int orderId, String orderName) {
		super();
		this.orderId = orderId;
		this.orderName = orderName;
	}
	
	
	public int getOrderId() {
		return orderId;
	}
	public void setOrderId(int orderId) {
		this.orderId = orderId;
	}
	public String getOrderName() {
		return orderName;
	}
	public void setOrderName(String orderName) {
		this.orderName = orderName;
	}
	
	@Override
		public boolean equals(Object obj) {
			if(this==obj)//先判断地址是否相同
			{	
				return true;
			}
			
			if(obj instanceof Order)
			{
				Order order=(Order)obj;
				//形参被赋值为order,即obj是Order的实例,如果不转的话,就没法order.属性了
				//正确的
				return this.orderId==order.orderId&&
						this.orderName.equals(order.orderName);
				
				
				//错误的,不要这样写(因为对于两种不同的String定义方式,用==比较的结果是不同的)
//				return this.orderId==order.orderId&&
//						this.orderName==order.orderName;
//		
			/*
			 * 当String 是通过String s1="BB";String s2="BB"的方式定义的,s1==s2和s1.equals(s2)二者是等价的。
			 * 因为equals首先比较的就是二者地址是否相同(可以在上边正确的点进去看一下),用这种方法定义的就是地址相同
			 * 但是用另外一种定义方法,那么指向的地址就不同了,故这是不对的不能用。见日记8
			 *  public boolean equals(Object anObject) {
        			if (this == anObject) {//判断地址是否相同
            			return true;
        		}
        			return (anObject instanceof String aString)
                			&& (!COMPACT_STRINGS || this.coder == aString.coder)
                			&& StringLatin1.equals(value, aString.value);
    			}
			 * 
			 * 
			 * 
			 * 
			 * 当String是通过String s1=new String("BB");String s2=new String("BB");的方式定义的话就地址不同了
			 * 即s1和s2执行堆空间中不同的内存。
			 */
			}
			return false;
		}
	
	

	
}

练习二

package com.atguigu.exer2;

import java.util.Objects;

/*
 * 请根据以下代码自行定义能满足需要的MyDate类,在MyDate类中覆盖equals方法,
 * 使其判断当两个MyDate类型对象的年月日都相同时,结果为true,否则为false。
 * public boolean equals(Object o)
 */

public class MyDateTest {

	public static void main(String[] args) {
		MyDate m1= new MyDate(14, 3, 1976);
		MyDate m2= new MyDate(14, 3, 1976);
		if(m1== m2) {
			System.out.println("m1==m2");
		} else{
			System.out.println("m1!=m2"); // m1 != m2
		}
		
		if(m1.equals(m2)) {
			System.out.println("m1 is equal to m2");// m1 is equal to m2
		} else{
			System.out.println("m1 is not equal to m2");
		}
	}
}


class MyDate
{
	private int day;
	private int month;
	private int year;
	public MyDate(int day, int month, int year) {
		super();
		this.day = day;
		this.month = month;
		this.year = year;
	}
	public int getDay() {
		return day;
	}
	public void setDay(int day) {
		this.day = day;
	}
	public int getMonth() {
		return month;
	}
	public void setMonth(int month) {
		this.month = month;
	}
	public int getYear() {
		return year;
	}
	public void setYear(int year) {
		this.year = year;
	}
	
	public boolean equals(Object obj)
	{
		if(this==obj)
		{
			return true;
		}
		if(obj instanceof MyDate)
		{
			MyDate myDate=(MyDate)obj;
			return this.day==myDate.day&&this.month==myDate.month&&this.year==myDate.year;
		}
		return false;
	}

	

	
}

7.3、toString的使用

package com.atguigu.java1;

import java.util.Objects;

public class Customer {

	private String name;
	private int 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 Customer(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	public Customer() {
		super();
	}

	
	
	
	
	
	
	//自动生成的,即实际开发中我们都不是手写的,都是调用的
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Customer other = (Customer) obj;
		return age == other.age && Objects.equals(name, other.name);
	}

	
	
	//手动实现equals()
//	为每个类重写equals(),原则:比较两个对象的实体内容(即,name和age)是否相同
//	@Override
//	public boolean equals(Object obj) {
//		
//		System.out.println("Customer equals…………");
//		  if (this == obj) {//如果二者的引用地址相同,就返回true
//	            return true;
//	        }
//		  if(obj instanceof Customer)
//		  {
//			  Customer cust=(Customer)obj;
//			  //比较两个对象的两个属性是否都相同

//			  return this.age==cust.age&&this.name.equals(cust.name);
//		  }
//		  return false;
//	}
	

	
	
	
	
	
	
	
	//手动实现重写toString类
//	@Override
//	public String toString() {
//		return "Custmoer[name = "+name+",age= "+age+"]";
//	}
	//自动实现
	@Override
	public String toString() {
		return "Customer [name=" + name + ", age=" + age + "]";
	}
	
	

	
}

ToStringTest类

package com.atguigu.java1;

import java.util.Date;
/*
 * Object类中toString()的使用
 * 
 * 1.当我们输出一个对象的引用时,实际上就是调用当前对象的toString(),可以点击println进入源码看一下,最终调用的是引用类型的tostring().
 * 2.Object类中toString的定义方法
 * 	public String toString() {
 *      return getClass().getName() + "@" + Integer.toHexString(hashCode());
 *  }//获取调用该方法的对象的类的类名+ "@" +位置:通过hashCode值计算出来一个在堆空间中的存储位置,并将其转化为16进制。
 * 
 * 3.像String、Date、File、包装类    等都重写了Object类中的toString()方法。
 * 	 使得在调用toString()时,返回"实体内容"信息.(关心什么就返回什么)
 * 	
 * 
 * 4.自定义类如果重写toString()方法,当调用此方法时,返回对象的"实体内容".
 * 
 * 注:以后想输出一个对象时,若想输出地址值,就直接输出;若不想输出地址值,那么就重写下toString
 */
public class ToStringTest {
	public static void main(String[] args) {
		
		Customer cust1 = new Customer("Tom" ,21);
		System.out.println(cust1.toString());	//com.atguigu.java1.Customer@6f2b958e---> Customer[name = Tom,age = 21]
		//(注意Java中的内存地址是一个虚拟的地址,在操作系统基础之上有JVM,JVM相当于一个虚拟的操作系统,地址是一个虚拟地址,并不是一个真实地址
		//是hashCode算出来的一个值。
		System.out.println(cust1); 	//com.atguigu.java1.Customer@6f2b958e ---> Customer[name = Tom,age = 21]
		
		String str = new String("MM");//重写过
		System.out.println(str);//MM
		
		Date date = new Date(45362348664663L);//重写过
		System.out.println(date.toString());	//Wed Jun 24 12:24:24 CST 3407
		
	}
}

练习
GeometricObject类

package com.atguigu.exer3;

//见日记10
public class GeometricObject {

	protected String color;
	protected double weight;
	
	
	public GeometricObject() {
		super();
		this.color="white";
		this.weight=1.0;
	}
	public GeometricObject(String color, double weight) {
		super();
		this.color = color;
		this.weight = weight;
	}
	
	

	public String getColor() {
		return color;
	}
	public void setColor(String color) {
		this.color = color;
	}
	public double getWeight() {
		return weight;
	}
	public void setWeight(double weight) {
		this.weight = weight;
	}
	
}

Circle类

package com.atguigu.exer3;

public class Circle extends GeometricObject {

	private double radius;

	public Circle() {
		super();
		radius=1.0;
//		color="white";
//		weight=1.0;冗余了,父类中的空参构造器中定义过了
	}

	public Circle(double radius) {
		super();
		this.radius = radius;
	}
	
	public Circle(double radius,String color,double weight) {
		super(color,weight);
		this.radius = radius;
	}

	public double getRadius() {
		return radius;
	}

	public void setRadius(double radius) {
		this.radius = radius;
	}
	
	//求圆的面积
	public double findArea()
	{
		return 3.14*radius*radius;
	}
	
	//比较两个圆的半径是否相等,如相等,返回true。
	@Override
	public boolean equals(Object obj) {
		if(this==obj)
		{
			return true;
		}
		if(obj instanceof Circle)
		{
			Circle c=(Circle)obj;
			return this.radius==c.radius;
		}
		return false;
	}

	@Override
	public String toString() {
		return "Circle [radius=" + radius + "]";
	}
	
	
	
	
}

测试类

package com.atguigu.exer3;

/*
 * 写一个测试类,创建两个Circle对象,判断其颜色是否相等;
 * 利用equals方法判断其半径是否相等;利用toString()方法输出其半径。
 * 
 */
public class CircleTest {

	public static void main(String[] args) {
		Circle circle1=new Circle(2.3);
		Circle circle2=new Circle(2.3, "white", 2.0);
		//或Circle circle2=new Circle(2.3, new String("white"), 2.0);
		
		System.out.println("颜色是否相等:"+circle1.getColor().equals(circle2.getColor()));
		//equals系统重写过
		System.out.println("半径是否相等:"+circle1.equals(circle2));
		
		System.out.println(circle1);
		System.out.println(circle2.toString());//即使重写了上边和下边的效果是一样的。
		
	}
	
}

08、包装类(Wrapper)的使用

8.1、单元测试方法的使用

package com.atguigu.java2;

import java.sql.Date;

import org.junit.Test;

/*
 * java中的JUnit单元测试
 * 
 * 步骤:
 * 1.选中当前项目工程 --》 右键:build path --》 add libraries --》 JUnit 4 --》 下一步
 * 2.创建一个Java类进行单元测试。
 * 	 此时的Java类要求:①此类是公共的 ②此类提供一个公共的无参构造器 
 * 3.此类中声明单元测试方法。
 *   此时的单元测试方法:方法的权限是public,没有返回值,没有形参。
 * 
 * 4.此单元测试方法上需要声明注解:@Test,并在单元测试类中调用:import org.junit.Test;
 * 5.声明好单元测试方法以后,就可以在方法体内测试代码。
 * 6.写好代码后,左键双击单元测试方法名:右键 --》 run as --》 JUnit Test
 * 
 * 说明:如果执行结果无错误,则显示是一个绿色进度条,反之,错误即为红色进度条。
 * 
 * 
 * 在实际操作中,不用这么麻烦,在公共类中直接@Test,
 * 然后创建一个权限是public,没有返回值,没有形参的方法
 * ,然后点一下系统提示要导入的包即可。B301
 */
public class JUnitTest {
	
	int num=10;//在单元测试里边不用再造对象了,直接可以看
	@Test
	public void testEquals()//方法名,一般测谁就起名test谁
	{
		String s1="MM";
		String s2="MM";
		System.out.println(s1==s2);
		System.out.println(s1.equals(s2));
		
		//类型转换异常ClassException
//		Object obj=new String("GG");
//		Date date=(Date)obj;
		
		System.out.println(num);//属性直接看
		show();//方法直接调,就看成普通方法一样就可以。
	}
	
	public void show()
	{
		num=20;
		System.out.println(num);
	}
	
	//再测量其他的就再造一个Test
	@Test
	public void testToString()
	{
		String s2="MM";
		System.out.println(s2.toString());
	}
	
	
	

}

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

8.2、包装类的使用

/*
 * 包装类的使用
 * 1.java提供了8种基本数据类型对应的包装类,使得基本数据类型的变量具有类的特征
 * 		基本数据类型		包装类
 * 		byte			Byte
 * 		short			Short
 * 		int 			Integer
 * 		long			Long
 * 		float			Float
 * 		double			Double
 * 		boolean			Boolean
 * 		char			Character
 * 注意:其中Byte、Short、Integer、Long、Float、Double的父类是:Number
 * /

8.3、包装类与基本数据类型相互转换

在这里插入图片描述

package com.atguigu.java2;
import org.junit.Test;
/*
 * 为什么要有包装类?
 * 为了是基本数据类型的变量具有类的特征,引入包装类。
 * 如有些方法的形参是Object,基本数据类型没法用,故使用包装类
 * 
 * 1.见日记11
 * java提供了8种基本数据类型对应的包装类,使得基本数据类型的变量具有类的特征
 * 		基本数据类型		包装类
 * 		byte			Byte
 * 		short			Short
 * 		int 			Integer
 * 		long			Long
 * 		float			Float
 * 		double			Double
 * 		boolean			Boolean
 * 		char			Character
 * 注意:其中Byte、Short、Integer、Long、Float、Double的父类是:Number
 * 
 * 
 *  2.基本数据类型、包装类、String三者之间的相互转换。
 * 
 * 注:见D,
 * 1.基本数据类型和包装类用自动装箱自动拆箱,然后记住     基本数据类型、和包装类与String类型的转化
 * 
 * 
 * 
 *	基本数据类型<--->包装类:JDK5.0 新特性:自动装箱与自动拆箱
 *	基本数据类型、包装类---->String:调用String重载的valueOf(Xxx xxx)
 *	String---->基本数据类型、包装类:调用包装类的parseXxx(String s)
 *
 *
 * 
 * 2.基本数据类型和包装类既然有自动装箱自动拆箱了,故将二者看成一个整体,与String类型进行转化
 * 3.
 * test1和test5中,可能会报NumberFormatException,如

	String str1 = "123a";int num2 = Integer.parseInt(str1); 
,Boolean除外,只要Boolean类型变量不是true的大小写都是false

*/



 
  
 
public class WrapperTest {
	
	//String类型---> 基本数据类型、包装类,调用包装类的parseXxx()
	@Test
	public void test5(){
		String str1 = "123";
//		String str1 = "123a";
			
		//错误的情况,可能会报错NumberFormatException,如上边一行转化成int就会报错
//		int num1 = (int)str1;//String类型不能和其他类型强转。
//		Integer in1 = (Integer)str1;//没有子父类关系的强转是会报错的
		
		int num2 = Integer.parseInt(str1); 
		System.out.println(num2 + 1);	//124
		
		String str2 = "True";//不是大小写都可以的true,就回输出false
		Boolean b1 = Boolean.parseBoolean(str2);
		System.out.println(b1);	//true
		
	}
	
	
	
	
	
	
	//基本数据类型、包装类---》String类型,调用String重载的valueOf(Xxx xxx)
	//不管是基本数据类型还是包装类都可以调用String.valueOf()方法。
	@Test
	public void test4(){
		int num1 = 10;
		//方式1:连接运算
		String str1 = num1 + "";//其他七种都可以,Boolean也行
		
		
		
		//方式2:调用String的valueOf(Xxx xxx)
		//2.1基本数据类型
		float f1 = 12.3f;
		String str2 = String.valueOf(f1); //"12.3"
		
		
		//2.2包装类
		Double d1 = new Double(12.4);
		String str3 = String.valueOf(d1);
		System.out.println(str2);
		System.out.println(str3);	//"12.4"
		
	}
	
	
	
	
	
	
	//基本数据类型和包装类既然有自动装箱自动拆箱了,故将二者看成一个整体,与String类型进行转化。看上边
	
	
	
	
	
	
	
	
	
	
	
	/*
	 * JDK 5.0 新特性:自动装箱与自动拆箱(即将基本数据类型和包装类的变量看成是同一个类型,直接赋值)
	 */
	@Test
	public void test3(){
		int num1 = 10;
//		//基本数据类型 --》 包装类的对象
		method(num1);	
		//并不是将int型的num1赋值给Object类型的变量,二者没有任何关系,即不是:Object obj = num1
		//而是用到了自动装箱,自动拆箱
		method( new Integer(num1));
		System.out.println((new Integer(num1).toString()));
		
		
		//自动装箱:基本数据类型 --》 包装类//直接将基本数据类型的变量赋值给包装类的变量就可以
		int num2 = 10;
		Integer in1 = num2;//自动装箱
		
		boolean b1 = true;
		Boolean b2 = b1; //自动装箱
		
		
		
		
		//自动拆箱:包装类 --》 基本数据类型//直接将包装类的对象赋值给基本数据类型的变量即可
		System.out.println(in1.toString());
		
		int num3 = in1;
		
		
	}
	
	public void method(Object obj){//将基本数据类型转化为包装类才可以调用此方法
		System.out.println(obj);//obj.toString();此为多态,包装类重写过该方法,因此调用的是子类重写的父类的方法
		//即(new Integer(num1)).toString(),整形包装类的toString,输出的是实体值10.
	}
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	//包装类 --》 基本数据类型:调用包装类的xxxValue()
	@Test
	public void test2() {
		Integer in1 = new Integer(12);
		int i1 = in1.intValue();
		System.out.println(i1 + 1); 
		
		Float f1 = new Float(12.3f);
		float f2 = f1.floatValue();
		System.out.println(f2 + 1); 
	}
	
	//基本数据类型--》包装类,调用包装类的构造器
	@Test
	public void test1() {
		int num1 = 10;
//		System.out.println(num1.toString());//报异常
		
		//方式1
		Integer in1 = new Integer(num1);
		System.out.println(in1.toString());//10,Integer重写了toString(),输出实体内容
		
		//方式2
		Integer in2 = new Integer("123");
		System.out.println(in2.toString());
		
		//报异常
//		Integer in3 = new Integer("123abc");//形参是字符串类型的话,只能是数字。
//		System.out.println(in3.toString());
		
		
		
		Float f1 = new Float(12.3f);
		Float f2 = new Float("12.3");
		System.out.println(f1);
		System.out.println(f2);
		
		Boolean b1 = new Boolean(true);
		Boolean b2 = new Boolean("TrUe");
		//true,对于Boolean类型的形参中的字符串形式忽略大小写,只要长得和true一样就行
				//只要不是true的形式,其他都是false
		System.out.println(b2);
		
		
		Boolean b3 = new Boolean("true123");
		System.out.println(b3); //false
		
		Order order = new Order();
		System.out.println(order.isMale); //false
		System.out.println(order.isFemale); //null
		
	}
}

class Order{
	
	boolean isMale;
	Boolean isFemale;
}

8.4、练习

1、面试题

package com.atguigu.java2;

import org.junit.Test;
/*	关于包装类使用的面试题
 * 
 * 
 * 如下两个题目输出结果相同吗?各是什么:
 * 		Object o1= true? new Integer(1) : new Double(2.0);
 * 		System.out.println(o1);//
 * 
 * 		Object o2;
 * 		if(true)
 * 			o2 = new Integer(1);
 *		else 
 *			o2 = new Double(2.0);
 *		System.out.println(o2);//
 *
 */
public class InterviewTest {

	@Test
	public void test1(){
		Object o1= true? new Integer(1) : new Double(2.0);
		//三元运算符,在进行运算时,要求二者可以统一成同一个类型
		//多态性是调用的是子类重写父类的方法,下边语句输出的是o1.toString(),Integer重写了该方法
		//实际输出的是实体的值
		System.out.println(o1);// 1.0//三元运算符有自动类型提升,会提升为1.0
	}
	
	@Test
	public void test2(){
		Object o2;
		if(true)
			o2 = new Integer(1);
		else 
			o2 = new Double(2.0);
		System.out.println(o2);//1
		// 对于引用类型输出的是  对象.toString();Object o2=new Integer().是多态,因此,调用的是子类Integer重写的父类的方法,
		//重写后是输出的实体内容。
	}
	
	
	
//对于println(形参),形参是char型数组,输出的是内容,除了char型数组之外的数组都是输出地址值。
		
	@Test
	public void test3() {
		Integer i = new Integer(1);
		Integer j = new Integer(1);
		System.out.println(i == j); //false
		









	    //Integer内部定义了一个IntegerCache结构,IntegerCache中定义Integer[]
		//保存了从-128-127范围的整数。如果我们使用自动装箱的方式,给Integer赋值的范围在-128-127内时,
		//可以直接使用数组中的元素,不用再去new了。而且使用完后数组中的元素不会销毁,只是将定义的变量销毁了,所用的元素还在数组中。
		//下次再用时还是用现成的就可以了。目的,提高效率。
	    //当整形变量范围不在-128-127范围内就会,在堆空间中new一个对象。
		
//		封装类包装类就是将将核心的基本数据类型的变量包了一下作为这个类的属性出现而已,另外加了一些方法
		Integer m = 1;//自动装箱
		Integer n = 1;
		System.out.println(m == n);//true
		
		
		
		
		
		
		
		Integer x = 128;//相当于new了一个Integer对象
		Integer y = 128;//相当于new了一个Integer对象
		System.out.println(x == y);//false

	}
}

2、编程题

在这里插入图片描述

package com.atguigu.exer4;

import java.util.Scanner;
import java.util.Vector;

/*
 * 
 * 注: 因为有些方法的形参是Object,基本数据类型没法用,故使用包装类
 *  
 *  
 * 利用Vector代替数组处理:从键盘读入学生成绩(以负数代表输入结束),
 * 找出最高分,并输出学生成绩等级。
 * 
 * 提示:数组一旦创建,长度就固定不变,所以在创建数组前就需要知道它的长度。
 * 而向量类java.util.Vector可以根据需要动态伸缩。
 * 
 * 创建Vector对象:Vector v=new Vector();
 * 给向量添加元素:v.addElement(Object obj);   //obj必须是对象
 * 取出向量中的元素:Object  obj=v.elementAt(0);
 * 注意第一个元素的下标是0,返回值是Object类型的。
 * 计算向量的长度:v.size();
 * 若与最高分相差
 * 		10分内:A等;
 * 		20分内:B等;
 * 		30分内:C等;
 * 		其它:D等
 * 
 */
public class ScoreTest {
	public static void main(String[] args) {
		// 1.实例化Scanner,用于从键盘获取学生成绩
		Scanner scan = new Scanner(System.in);

		// 2.创建Vector对象:Vector v=new Vector();相当于原来的数组
		Vector v = new Vector();

		// 3.通过for(;;)或while(true)方式,给Vector中添加数组
		int maxScore = 0;
		for (;;) {
			System.out.println("请输入学生成绩(以负数代表输入结束)");
			int score = scan.nextInt();
			// 3.2 当输入是负数时,跳出循环
			if (score < 0) {
				break;
			}
			if (score > 100) {
				System.out.println("输入的数据非法,请重新输入");
				continue;
			}
			
			// 3.1 添加操作::v.addElement(Object obj)
			// jdk5.0之前:
			// Integer inScore = new Integer(score);
			// v.addElement(inScore);//多态,运行子类(Integer)重写的inScore.toString();
			// jdk5.0之后:
			v.addElement(score);// 自动装箱,即直接可以将整形赋值给Object类
			
			// 4.获取学生成绩的最大值
			if (maxScore < score) {
				maxScore = score;
			}
		}

		// 5.遍历Vector,得到每个学生的成绩,并与最大成绩比较,得到每个学生的等级。
		char level=0;
		for (int i = 0; i < v.size(); i++) {
			Object obj = v.elementAt(i);
			// jdk 5.0之前:
//			 Integer inScore = (Integer)obj;
//			 int score = inScore.intValue();
			// jdk 5.0之后:
			int score = (int) obj;

			if (maxScore - score <= 10) {
				level = 'A';
			} else if (maxScore - score <= 20) {
				level = 'B';
			} else if (maxScore - score <= 30) {
				level = 'C';
			} else {
				level = 'D';
			}

			System.out.println("student " + i + " score is " + score + ",level is " + level);

		}
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值