1、static

1.1、static静态变量

static表示静态,是Java中的一个修饰符,可以修饰成员方法,成员变量。(被static修饰的成员方法或者成员变量是共享的,谁用谁去拿)

(1)、被static修饰的成员变量,叫做静态变量。

特点:被该类所有对象共享。不属于对象,属于类。随着类的加载而加载的,优先于对象出现的。静态的内容不会随着对象的变化而变化。

调用方式:类名调用(推荐)、对象名调用。

(2)、被static修饰的成员方法,叫做静态方法。

特点:多用在测试类和工具类当中。javabean类中很少会用。

调用方式:类名调用(推荐)、对象名调用。

复习目前所学过的所有的类

1、JavaBean类用来描述一类事物的类。比如:Student、Teacher、Dog、Cat等等。书写JavaBean类的时候,要私有化成员变量,书写空参构造方法,书写带全部参数的构造方法,还需要针对每一个私有化的成员变量提供其对应的get()和set()方法,如果说还有额外的行为,比如sleep或study等等,还有一些额外的成员方法。核心在于JavaBean类是用来描述一类事物的。
2、测试类用来检查其他类是否书写正确,带有main方法的类,是程序的入口。在测试类当中,创建JavaBean类的对象并进行赋值调用的。
3、工具类不是用来描述一类事物的,而是帮我们做一些事情的类。特点:(1)、类名见名知意。(2)、私有化构造方法。为了不让外界创建这个类的对象,因为即使创建了也没意义。(3)、方法定义为静态。

案例1:用static修饰成员变量。

需求:写一个javab类来描述这个班级的学生。属性有:姓名、年龄、性别。行为有:学习。

package FFFFFF;public class Student {private String name;private int age;private String gender;//新增教师姓名属性,所有同学都一个老师public  static String teacherName;public Student() {}public Student(String name, int age, String gender) {this.name = name;this.age = age;this.gender = gender;}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 String getGender() {return gender;}public void setGender(String gender) {this.gender = gender;}//行为public void study(){System.out.println(name + "正在学习");}//public void show(){System.out.println(name + "," + age + "," + gender + "," + teacherName);}}
package FFFFFF;public class StudentTest {public static void main(String[] args) {Student.teacherName = "大何老师";   //利用类名调用静态变量//1、创建第一个学生对象Student s1 = new Student();s1.setName("张三");s1.setAge(23);s1.setGender("男");//s1.teacherName = "大何老师";  //利用对象名调用静态变量/**分析:* 1、如果Student类中的teacherName不用static修饰,*   1.1、  s1和s2都不给teacherName赋值的时候,s1和s2的teacherName输出值为null。*   1.2、 只有s1给teacherName赋值的时候,s1的teacherName输出为赋的值,s2的teacherName输出值为null。* 2、如果Student类中的teacherName用static修饰,*   2.1、 s1和s2都不给teacherName赋值的时候,s1和s2的teacherName输出值为null。*   2.2、 s1和s2中只要有一个给teacherName赋值,s1和s2的teacherName输出值都为赋的值。*   2.3、利用类名调用静态变量,对teacherName进行赋值,则s1和s2的teacherName输出值都为赋的值。*/s1.study();s1.show();/**竖着批量修改,比如把本题中s1改为s2,方便快捷* 方法1:按住鼠标滚轮,滑动鼠标选择修改的范围* 方法2:按住alt,然后按住鼠标左键选择修改的范围*///1、创建第二个学生对象Student s2 = new Student();s2.setName("李红");s2.setAge(21);s2.setGender("女");s2.study();s2.show();}
}

案例2:定义数组工具类。

需求:在实际开发当中,经常会遇到一些数组使用的工具类。请按照以下要求编写一个数组的工具类:ArrayUtil。

(1)、提供一个工具类方法printArr,用于返回整数数组的内容。返回的字符串格式如下:

[10,20,50,34,100] (只考虑整数型数组,且只考虑一维数组)

(2)、提供这样一个工具方法getAerage,用于返回平均分。(只考虑浮点型数组,且只考虑                一维数组)

(3)、定义一个测试类TestDome,调用该工具类的工具方法,并返回结果。

package Test01;public class ArrayUtil {//私有化构造方法//目的:为了不让外界创建他的对象private ArrayUtil(){}//需要定义为静态的,方便调用public static String printArr(int[] arr){StringBuilder sb = new StringBuilder();sb.append("[");for (int i = 0; i < arr.length; i++) {if(i == arr.length - 1){sb.append(arr[i]);} else {sb.append(arr[i]).append(",");}}sb.append("]");return sb.toString();}public static double getAerage(double[] arr){double sum = 0;for (int i = 0; i < arr.length; i++) {sum = sum + arr[i];}double aerage = sum/arr.length;return aerage;}
}
package Test01;public class TestDome {public static void main(String[] args) {int[] arr1 = {1,2,3,4,5};String str = ArrayUtil.printArr(arr1);System.out.println(str);double[] arr2 = {1.2,2.2,3.2};double str2 = ArrayUtil.getAerage(arr2);System.out.println(str2);}
}

案例3:定义学生工具类。

需求:定义一个集合,用于存储3个学生对象。

学生的属性为:name、age、gender。

定义一个工具类,用于获取集合中最大学生的年龄。

package testDome02;public class Student {private String name;private  int age;private String gender;public Student() {}public Student(String name, int age, String gender) {this.name = name;this.age = age;this.gender = gender;}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 String getGender() {return gender;}public void setGender(String gender) {this.gender = gender;}
}
package testDome02;import java.util.ArrayList;public class StudentUtil {private StudentUtil(){}//静态方法public static int getMaxAAgeStudent(ArrayList<Student> list){//定义一个参照物int max = list.get(0).getAge();for (int i = 1; i < list.size(); i++) {int temp = list.get(i).getAge();if( temp > max){max = temp;}}return max;}
}
package testDome02;import java.util.ArrayList;public class tset {public static void main(String[] args) {//创建一个集合用来存储学生对象ArrayList<Student> list = new ArrayList<>();//创建3个学生对象Student stu1 = new Student("张三",23,"男");Student stu2 = new Student("小红",18,"女");Student stu3 = new Student("王二",21,"男");list.add(stu1);list.add(stu2);list.add(stu3);//调用工具类中的方法int maxAgeStudent = StudentUtil.getMaxAAgeStudent(list);System.out.println(maxAgeStudent);}}

1.2、static的注意事项

1、静态方法只能访问静态。

2、非静态方法可以访问所有。

3、静态方法中没有this关键字。

1.3、静态方法内容补充:

1、在定义方法的时候,在修饰符的位置加上static,这个方法就是一个静态方法
2、静态方法,可以通过类名去访问,也可以通过对象名去访问
3、只能能通过类名去访问的内容,本质上都是属于类最好都通过类名去访问
4、静态方法使用注意事项:
(1)、静态方法中不能访问成员变量静态方法,可以在没有创建对象的时候就可以调用,成员变量是在对象完成之后才可以使用,如果静态的方法可以访问成员变量,就相当于在创建对象之前,就使用对象内容
(2)、静态方法能不能访问成员方法,不能,原理同上
(3)、静态方法只能访问静态的内容,可以访问静态的属性,也可以访问静态的方法
(4)、静态方法能不能有this关键字,this表示本类当前对象,有了对象才有this,所以还是不行
5、总结:
(1)、静态的内容不可以访问非静态的内容,非静态的内容可以访问静态的内容

1.4、静态变量和非静态变量的区别

1、概念上所属不同:(1)、非静态变量属于对象(2)、静态变量属于类
2、内存空间位置不同:(1)、非静态变量存储在堆内存中,和对象一个区域(2)、静态变量属于类,和类.class文件在一个区域,都在方法区中,只不过静态变量在静态区
3、存储的时间不同,生命周期不同(1)、非静态变量属于对象,所以生命周期和对象一致,随着对象的创建而创建,随着对象的消亡而消亡(2)、静态变量属于类,所以生命周期和类一致,随着类的加载而加载,.class的销毁而销毁
4、访问方式的不同:(1)、非静态变量,只能通过对象名访问(2)、静态变量,既可以通过类名访问,也可以通过对象名来访问

2、继承

2.1继承的概述

1、继承

(1)、继承是面向对象的三大特征之一,可以让类和类之间产生子父关系。

(2)、Java中提供一个关键字extends,用这个关键字,我们可以让一个类和另一个类建立起继承关系。

public class Student extends Person {}

Student称为子类(派生类),Person称为父类(基类或者超类)。

2、使用继承的好处:

(1)、可以把多个子类中重复的代码抽取到父类当中,提高代码的复用性。

(2)、子类可以在父类的基础上,增加其他的功能,使子类更强大。子类拥有父类的所有功能。

(3)、子类可以得到父类的属性和行为,子类可以使用父类的属性和行为。

3、什么时候用继承?

当类与类之间,存在相同(共性)的内容,并满足子类是父类中的一种,就可以考虑使用继承,来优化代码。

4、继承的好处和弊端

(1)、好处:

a、提高了代码的复用性

b、提高了代码的可维护性

c、是类中多态的前提

(2)、弊端:

提高了代码和代码的耦合性(耦合性:事物和事物之间互相影响的程度)

(3)、开发原则:高内聚、低耦合。

(4)、继承的好处远远大于弊端,所以继承还是要用。

2.2、继承的特点

Java只支持单继承,不支持多继承,单支持多层继承

(1)、单继承:一个子类只能继承一个直接父类。

(2)、不支持多继承:子类不能同时继承多个父类。

(3)、多层继承:子类A继承父类B,父类B可以继承父类C。

(4)、每一个类直接或简介继承于Object(由Java虚拟机自动调用)

(5)、子类可以用间接父类(间接父类类似于现实生活当中的爷爷)中的变量与方法。

(6)、父类中的私有成员不能被继承(不能在子类中直接访问)

a、父类中的一些私有成员,不能在子类中直接调用。

b、其实在子类对象中,仍然包含父类这些私有的成员变量。

c、只不过在子类中,不能直接使用这些私有的内容,需要通过公共的访问方式访问。

案例1:

package EXTENDS;public class Animal {//权限修饰符//private:子类就无法访问了//私有:只能在本类中访问,比如爸爸的私房钱儿子是不能用的//子类只能访问父类中非私有的成员public void eat(){System.out.println("吃东西");}public void drink(){System.out.println("喝水");}
}
package EXTENDS;public class cat extends Animal {public void catchMouse(){System.out.println("猫抓老鼠");}
}
package EXTENDS;public class Dog extends Animal {public void lookHome(){System.out.println("狗在看家");}
}
package EXTENDS;public class Husky extends Dog{public void breakHome(){System.out.println("哈士奇在拆家");}
}
package EXTENDS;public class LiHua extends cat{}
package EXTENDS;public class Ragdoll extends cat {}
package EXTENDS;public class Teddy extends Dog{public void touch(){System.out.println("泰迪又在蹭我的腿了");}
}
package EXTENDS;public class Test {public static void main(String[] args) {Ragdoll ad = new Ragdoll();ad.eat();ad.drink();ad.catchMouse();Husky hs = new Husky();hs.eat();hs.drink();hs.breakHome();hs.lookHome();LiHua lh = new LiHua();lh.catchMouse();}
}

2.3、继承中成员变量的访问特点:

1、就近原则、直接用变量名

2、在用本类中的值:this.变量名

3、用父类中的值:super.变量名

(先在局部位置找,本类成员位置找,父类成员位置找,逐级往上)

(this和super是在子类中使用的,不是在测试类当中使用的)

(变量:从局部位置开始往上找)

(this.变量:从本类成员位置开始往上找)

(super.变量:从父类成员位置开始往上找)

案例:

package Diaoyong;public class Test {public static void main(String[] args) {er er1 = new er();er1.zishu();}
}class fu {String name = "funame";
}
class er extends fu {String name = "ziname";public void zishu(){String name = "输出名字";System.out.println(name);System.out.println(this.name);System.out.println(super.name);}
}

2.4、继承中:成员方法的访问特点

直接调用满足就近原则:谁离我近,我就调用谁

this调用,就近原则。

super调用,直接访问父类。

(this和super是在子类中使用的,不是在测试类当中使用的)

(变量:从局部位置开始往上找)

(this.变量:从本类成员位置开始往上找)

(super.变量:从父类成员位置开始往上找)

package cyff;public class test {public static void main(String[] args) {Student s= new Student();s.lunch();}
}class Person{public void eat(){System.out.println("吃米饭,吃菜");}public void drink(){System.out.println("喝开水");}
}class Student extends Person{public void lunch(){this.eat();this.drink();super.eat();super.drink();}public void eat(){System.out.println("chifan");}public void drink(){System.out.println("heshui");}
}

继承中成员方法的相关补充:

1、在父子类中,如果写的都是不同名的方法,则子类既可以访问父类,也可以访问子类本身。

2、出现了同名的方法时,在子类调用这个方法的时候,只有子类对这个方法的实现。

3、如果父类和子类的方法名相同,但是实现不同,Java把这个叫做方法的重写。

a、重载:在一个类中,方法名相同,参数列表不同,与返回值类型无关。

b、重写:在父子类中,方法名一样,参数列表一致,返回值类型一致,实现体不同。

c、Java中可以通过@Override检测一个方法是否是重写父类的方法。

补充: 方法的重写

定义:把父类的方法在子类里面重写一遍。

当父类的方法不能满足子类现在的需求时,需要进行方法重写。

重写的本质:方法被重写之后,相当于覆盖掉了父类中的方法。

方法重写注意事项和要求

1、重写方法的名称、形参列表必须与父类中的保持一致。
2、子类重写父类方法时,访问权限子类必须大于等于父类(暂时了解:空着不写 < protected < public)
3、子类重写父类方法时,返回值类型子类必须小于等于父类。
4、建议:重写的方法尽量和父类保持一致。(重点强调)
5、私有方法不能被重写。
6、子类不能重写父类的静态方法,如果重写会报错的。
补充:5和6总结起来就是“只有被添加到虚方法表中的方法才能被重写”

练习案例1:利用方法的重写设计继承结构

现在有三种动物:哈士奇、沙皮狗、中华田园犬。

暂时不考虑属性,只要考虑行为。

请按照继承的思想特点进行继承体系的设计。

分析如下:

package JiCheng;import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;public class test {public static void main(String[] args) {HaShiQi h = new HaShiQi();h.eat();h.drink();h.home();h.chaijia();System.out.println("--------------");ShaPiGou s = new ShaPiGou();s.eat();s.drink();s.home();System.out.println("--------------");ZhongHua z = new ZhongHua();z.eat();z.drink();z.home();}
}//定义动物类
class Animal{public void eat(){System.out.println("吃狗粮");}public void drink(){System.out.println("喝水");}public void home(){System.out.println("看家");}
}//定义哈士奇
class HaShiQi extends Animal{public void chaijia(){System.out.println("拆家");}
}//定义沙皮狗
class ShaPiGou extends Animal{//因为沙皮狗吃的狗粮和骨头//父类中的方法不能满足我们的需求了,所以需要进行重写。@Overridepublic void eat(){super.eat();    //吃狗粮System.out.println("吃骨头");}
}
//定义中华田园犬
class ZhongHua extends Animal{//父类中的方法不能满足我们的需求了,所以需要进行重写//而且中华田园犬完全用不到父类中的代码,所以不需要通过super进行调用。@Overridepublic void eat(){System.out.println("吃剩饭");}
}

2.5、继承中:构造方法的访问特点

package WCGZ;public class Test {public static void main(String[] args) {Student s1 = new Student();Student s2 = new Student("张三",23);System.out.println(s2.name + "," + s2.age);}}
class Person{String name;int age;public Person(){System.out.println("父类无参构造");}public Person(String name,int age){this.name=name;this.age=age;}
}class Student extends Person{public Student(){//子类构造方法中隐藏的super()去访问父类的无参构造super();    //调用了父类的无参构造System.out.println("子类的无参构造");}//给父类变量赋值public Student(String name,int age){super(name,age);    //调用了父类的有参构造}}输出为下:
父类无参构造
子类的无参构造
张三,23

对2.5进行小结:继承中构造方法的访问特点是什么?

1、子类不能继承父类的构造方法,但是可以通过super调用。

2、子类构造方法的第一行,有一个默认的super();

3、默认先访问父类中无参的构造方法,再执行自己。

4、如果不想调用父类中的无参构造,想要调用父类当中的有参构造,给成员变量赋值,则super需要自己写,而且要把赋值的数据写在小括号当中就可以了。

5、this语句和super语句只能出现在构造方法的第一行,而且只能出现一个。

this、super使用总结

this:理解为一个变量,表示当前方法调用者的地址值。

super:代表父类存储空间。

注意:要给一些数据设置一些默认值的时候就会用到this(....)访问本类构造方法。

1、含义:this表示本类当前对象的引用super表示本类当前对象父类部分的引用,哪个对象调用super所在的方法,super就代表哪个对象父类部分的数据
2、super和this都可以访问成员变量super只能访问父类中的成员变量this既可以访问父类中的成员变量,也可以访问子类中的成员变量
3、this和super都可以访问成员方法this既可以访问父类中的成员方法,也可以访问子类的super只能访问父类中的成员方法,格式  super.成员方法名(实际参数)
4、super和this都可以在构造方法中使用,但是使用的特点不同,可以用来访问构造方法的内容,this访问叫做this语句,super访问叫做super语句this(实际参数);访问子类的构造方法super(实际参数);访问父类的构造方法super语句和this语句,只能出现在构造方法的第一行,其他位置均不可以
package FWQT;public class Test {public static void main(String[] args) {Student s = new Student();System.out.println(s.name + "," + s.age + "," + s.school);//输出为  null,0,传智大学}
}class Student{String name;int age;String school;public Student() {//表示调用本类其他构造方法//细节:虚拟机就不会再添加super();this(null,0,"传智大学");//System.out.println("123");     //如果写在this语句的上面系统就会报错}public Student(String name, int age, String school) {this.name = name;this.age = age;this.school = school;}}

练习案例3:带有继承结构的标准Javabean类

父类代码如下:

package AL01;public class Employee {/*** 1.类名见名知意* 2.所有的成员变量都需要私有* 3.构造方法(空参  带全部参数的构造)* 4.get/set*///id,name,salary三种变量,经理和厨师都有,所以把它们抽取到父类Person当中private String id;private String name;private double salary;public Employee() {}public Employee(String id, String name, double salary) {this.id = id;this.name = name;this.salary = salary;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public double getSalary() {return salary;}public void setSalary(double salary) {this.salary = salary;}//工作和吃饭这两种方法,经历和厨师都有,所以把他们抽取到父类Person当中//工作public void work(){System.out.println("员工在工作");}//吃饭public void eat(){System.out.println("吃米饭");}
}

经理模块代码如下:

package AL01;public class Manager extends Employee {//因为父类当中的成员变量只有id,name,salary,不能满足子类需求,所以还需要添加变量jiangjinprivate double jiangjin;/**标准JavaBean类要求要有无参和全参构造。* 方法:Alt+Insert,然后全选,然后确定,再确定即可*///空参构造public Manager() {}//带全部参数的构造(父类+子类)public Manager(String id, String name, double salary, double jiangjin) {super(id, name, salary);this.jiangjin = jiangjin;}/**关于get和set方法,* 因为父类当中已经有id,name,salary的set、get方法了* 所以在这里就不需要再书写*只需要写父类当中没有的jiangjin的set、get方法*/public double getJiangjin() {return jiangjin;}public void setJiangjin(double jiangjin) {this.jiangjin = jiangjin;}//因为父类当中的work方法并不能满足子类要求,所以要重写work方法@Overridepublic void work(){System.out.println("管理其他人");}
}

厨师模块如下:

package AL01;public class Cook extends Employee {//1、因为父类当中的成员变量有id,name,salary,能满足子类需求,所以不需要再添加变量//2、构造方法一定要写//空参构造public Cook() {}//全参构造public Cook(String id, String name, double salary) {super(id, name, salary);}//3、关于get和set方法,// 因为父类当中有id, name, salary的set、get方法,所以这里就不用写了//因为父类当中的work方法并不能满足子类要求,所以要重写work方法@Overridepublic void work(){System.out.println("厨师在炒菜");}
}

测试类模块如下:

package AL01;public class Test {public static void main(String[] args) {//创建对象并赋值调用Manager m = new Manager("001","张三",1500,6000);System.out.println(m.getId() + "," + m.getName() + "," + m.getSalary() + "," + m.getJiangjin());m.work();m.eat();Cook c = new Cook();c.setId("002");c.setName("李四");c.setSalary(666);System.out.println(c.getId() + "," + c.getName() + "," + c.getSalary());c.work();c.eat();}
}

输出结果为:

001,张三,1500.0,6000.0
管理其他人
吃米饭
002,李四,666.0
厨师在炒菜
吃米饭

练习案例4:带有继承结构的标准JavaBean类

在黑马程序员中有很多员工(Employee)

按照工作内容不同分教研部员工(Teacher)和行政部员工(AdminStaff)

1、教研部根据教学的方式不同又分为讲师(Lecturer)和助教(Tutor)

2、行政部根据负责事项不同,又分为维护专员(Maintainer),采购专员(Buyer)

3、公司的每一个员工都有编号,姓名和其负责的工作

4、每个员工都有工作的功能,但是具体的工作内容又不一样

父类代码如下:

package YuanGong;public class Employee {private String bianhao;private String name;public Employee() {}public Employee(String bianhao, String name) {this.bianhao = bianhao;this.name = name;}public String getBianhao() {return bianhao;}public void setBianhao(String bianhao) {this.bianhao = bianhao;}public String getName() {return name;}public void setName(String name) {this.name = name;}public void work(){System.out.println("员工在工作");}
}
package YuanGong;public class JiaoYanBu extends Employee {public JiaoYanBu() {}public JiaoYanBu(String bianhao, String name) {super(bianhao, name);}
}
package YuanGong;public class XingZhengBu extends Employee {public XingZhengBu() {}public XingZhengBu(String bianhao, String name) {super(bianhao, name);}
}

子类代码如下:

package YuanGong;public class JiangShi01 extends JiaoYanBu {public JiangShi01() {}public JiangShi01(String bianhao, String name) {super(bianhao, name);}@Overridepublic void work(){System.out.println("讲师在工作");}
}
package YuanGong;public class ZhuJiao02 extends JiaoYanBu{public ZhuJiao02() {}public ZhuJiao02(String bianhao, String name) {super(bianhao, name);}@Overridepublic void work(){System.out.println("助教在工作");}
}
package YuanGong;public class WeiHu03 extends XingZhengBu {public WeiHu03() {}public WeiHu03(String bianhao, String name) {super(bianhao, name);}@Overridepublic void work(){System.out.println("维护员在工作");}
}
package YuanGong;public class CaiGou04 extends XingZhengBu{public CaiGou04() {}public CaiGou04(String bianhao, String name) {super(bianhao, name);}@Overridepublic void work(){System.out.println("采购员在工作");}
}

测试类代码如下:

package YuanGong;public class Test {public static void main(String[] args) {JiangShi01 js = new JiangShi01("001","张三");System.out.println(js.getBianhao() + "," + js.getName());js.work();ZhuJiao02 zj = new ZhuJiao02("002","李四");System.out.println(zj.getBianhao() + "," + zj.getName());zj.work();WeiHu03 wh = new WeiHu03("003","王二");System.out.println(wh.getBianhao() + "," + wh.getName());wh.work();CaiGou04 cg = new CaiGou04("004","麻子");System.out.println(cg.getBianhao() + "," + cg.getName());cg.work();}
}

3 多态

3.1 什么是多态?

同类型的对象,表现出的不同形态。

多态的表现形式

父类类型 对象名称 = 子类对象;
例如:
Person p = new Student();

多态的前提

1、有继承的关系或者实现关系
2、有父类引用指向子类对象   Fu f = new Zi();
3、有方法重写

多态的好处

使用父类型作为参数,可以接收所有子类对象,从而体现了多态的扩展性与便利。

案例1

父类代码如下:

package DuoTai;public class Person {private String name;private int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public void show(){System.out.println(name + "," + age);}
}

子类代码如下:

package DuoTai;public class Student extends  Person{public Student() {}public Student(String name, int age) {super(name, age);}@Overridepublic void show(){System.out.println("学生的信息为:" + getName() + "," + getAge());}
}
package DuoTai;public class Teacher extends  Person {public Teacher() {}public Teacher(String name, int age) {super(name, age);}@Overridepublic void show(){System.out.println("教师的信息为:" + getName() + "," + getAge());}
}
package DuoTai;public class Admin extends Person {public Admin() {}public Admin(String name, int age) {super(name, age);}@Overridepublic void show(){System.out.println("管理员的信息为:" + getName() + "," + getAge());}
}

测试类代码如下:

package DuoTai;public class Test {public static void main(String[] args) {//创建三个对象,并调用register方法Student s = new Student();s.setName("张三");s.setAge(18);Teacher t = new Teacher();t.setName("李华");t.setAge(25);Admin ad = new Admin();ad.setName("管家");ad.setAge(35);register(s);register(t);register(ad);}//既然这个方法既能接收老师,又能接收老师,还能接收管理员//只能把参数写成这三个类型的父类public static void register(Person p){p.show();}
}

3.2 多态调用成员变量的特点

变量调用:编译看左边,运行也看左边。

方法调用:编译看左边,运行看右边。

案例实现:

package DuoTaiA;public class Test {public static void main(String[] args) {//创建对象 (多态方式)//Fu f = new Zi();Animal a = new Dog();/**调用成员变量:编译看左边,运行也看左边* 编译看左边:javac编译代码的时候,会看左边的父类中有没有这个变量,如果有,编译成功,如果没有编译失败。* 运行也看左边:java运行代码的时候,实际获取的就是左边父类中的成员变量的值*/System.out.println(a.name);//动物/**调用成员方法:编译看左边,运行看右边* 编译看左边:javac编译代码的时候,会看左边的父类中有没有这个方法,如果有,编译成功,如果没有编译失败。* 运行也看左边:java运行代码的时候,实际获取的就是子类中的方法。*/a.show();   //Dog---show方法/**理解方法:* Animal a = new Dod();* 现在用a去调用变量和方法* 而a是Animal类型的,所以默认都会从Animal这个类中去找** 成员变量:在子类的对象中,会把父类的成员变量也继承下去。 父:name   子:name,因为父类的变量还在,所以用了父类的变量* 成员方法:如果子类对方法进行了重写,那么在虚方法表中是会把父类的方法进行覆盖的。父类的方法被覆盖了(相当于不在了)所以调用了子类的方法*/}
}
class Animal{String name = "动物";public void show(){System.out.println("Animal---show方法");}
}class Dog extends Animal{String name = "狗";@Overridepublic void show(){System.out.println("Dog---show方法");}
}class Cat extends Animal{String name = "猫";@Overridepublic void show(){System.out.println("Cat---show方法");}
}

3.3 多态的优势与弊端

1、多态的优势

a、在多态形式下,右边对象可以实现解耦合,便于扩展和维护。(修改下面被红线圈中的部分即可)

b、定义方法的时候,使用父类型作为参数,可以接收所有子类对象,体现多态的扩展性与便利。

由于参数为Object类,所以可以添加任何类,因为Object类是所有类的父类。

2、多态的弊端是:不能使用子类的特有功能。(重点!!!)

3、 引用数据类型的类型转换,有几种方式?

自动类型转换属于向上转型,是多态的体现,本质上缩小了对象本身访问的范围,减少了访问权限,只能访问父类中的内容,而不能访问子类特有的内容。(由于继承关系,父类的内容子类都有,但是子类中的内容父类不一定有,所以子类的内容父类多。)

强制类型转换属于向下转型,前提条件为一定是一个向上转型的对象。本质上是恢复子类本身的访问范围。

注意:不可以把父类对象进行向下转型,必须是父类的引用指向子类对象这种类型,才可以向下转型。

4、 强制类型转换能解决哪些问题?

可以转换成真正的子类类型,从而调用子类独有功能。

转换类型与真实对象类型不一致会报错 。

转换的时候用instanceof关键字进行判断。

instanceof关键字案例实践如下:

package DTBD;public class Test {public static void main(String[] args) {//创建对象Animal a = new Dog();//编译看左边,运行看右边a.eat();    //狗在吃骨头/**多态的弊端* 不能调用子类的特有功能,比如Dog里面的lookHome,还有Cat里面的catchMouse* 例如:a.lookHome();  系统会报错* 因为当调用成员方法的时候,编译看左边,运行看右边。* 那么在编译的时候会先检查左边的父类中有没有这个方法,如果没有直接报错。*//**弊端的解决方案:* 变回原来的子类型就可以了,例如:把Animal类型的变量a转换成Dog类型,然后就可以调用子类Dog当中的lookHome了* 细节:转换的时候,不能瞎转,如果转换成其他类的类型,就会报错,例如把上* 面的Animal类型的变量a转换成Cat类型就会报错*///Dog d = (Dog) a;//d.lookHome();   //狗在看家if(a instanceof  Dog){Dog d = (Dog) a;d.lookHome();} else if(a instanceof Cat){Cat c = (Cat)  a;c.catchHouse();} else {System.out.println("没有这个类型无法转换");}//java14新特性//先判断a是否为Dog类型,如果是,则强转成Dog类型,转换之后变量名为d//如果不是Dog类型,则不强转,结果直接是false/*if(a instanceof  Dog d){d.lookHome();} else if(a instanceof Cat c){c.catchHouse();} else {System.out.println("没有这个类型无法转换");}*/}
}
class Animal{public void eat(){System.out.println("动物在吃东西");}
}class Dog extends Animal{@Overridepublic void eat(){System.out.println("狗在吃骨头");}public void lookHome(){System.out.println("狗在看家");}
}class Cat extends Animal{@Overridepublic void eat(){System.out.println("猫在吃小鱼干");}public void catchHouse(){System.out.println("猫捉老鼠");}
}

3.4 多态的综合练习

分析如下:

父类代码如下:

package DTZHLX;public class Animal {private int age;private String color;public Animal() {}public Animal(int age, String color) {this.age = age;this.color = color;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}public void eat(String something){System.out.println("动物在吃"+something);}
}

子类代码如下:

package DTZHLX;public class Dog  extends Animal{public Dog() {}public Dog(int age, String color) {super(age, color);}//行为://eat(String something)(something表示吃的东西)//看家lookHome方法(无参数)@Overridepublic void eat(String something){//由于继承关系,getAge()+"岁的"+getColor()会自动调用父类当中对应的的get方法System.out.println(getAge()+"岁的"+getColor()+"颜色的狗两只前腿死死地抱住"+something+"猛吃");}//书写Dog类型特有的方法public void lookHome(){System.out.println("狗在看家");}
}
package DTZHLX;public class Cat extends Animal {public Cat() {}public Cat(int age, String color) {super(age, color);}//eat(String something)方法(something表示吃的东西)//捉老鼠catchHouse方法(无参数)@Overridepublic void eat(String something){//由于继承关系,getAge()+"岁的"+getColor()会自动调用父类当中对应的的get方法System.out.println(getAge()+"岁的"+getColor()+"颜色的猫眯着眼睛侧着头吃"+something);}//书写Cat类型特有的方法public void catchHouse(){System.out.println("猫在捉老鼠");}
}

Person类代码如下:

package DTZHLX;public class Person {private String name;private int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}/**Animal dongwu利用多态* instanceof的作用是判断,dongwu instanceof Dog是对输入的参数dongwu进行判断,判断是否为Dog类型* 如果是Dog类型,则如果没有对dongwu进行强制转换,则不能调用子类特有的方法。例如下面标* 记处1如果没执行,则标志处2会报错。但是无论有没有标记处1,标志处3都不受影响*/public void keepPet(Animal dongwu, String something){if(dongwu instanceof Dog){Dog d =( Dog )dongwu;   //标记处1System.out.println("年龄为"+age+"岁的"+name+"养了一只"+dongwu.getColor()+"颜色的"+dongwu.getAge()+"岁的狗");   //标志处3dongwu.eat(something);  //调用子类重写的方法d.lookHome();   //标志处2,调用Dog类特有的方法} else if(dongwu instanceof Cat){Cat c = ( Cat )dongwu;System.out.println("年龄为"+age+"岁的"+name+"养了一只"+c.getColor()+"颜色的"+c.getAge()+"岁的猫");c.eat(something);} else{System.out.println("没有这种动物");}}
}

测试类代码如下:

package DTZHLX;public class Test {public static void main(String[] args) {//由于多态的存在,创建Person对象的时候,只需要创建一个就行了Person p = new Person("老王",36);Dog d = new Dog(8,"黑");p.keepPet(d,"骨头");System.out.println("----------------------");Cat c = new Cat(9,"黄");p.keepPet(c,"鱼");}}

代码运行后,输出结果如下:

年龄为36岁的老王养了一只黑颜色的8岁的狗
8岁的黑颜色的狗两只前腿死死地抱住骨头猛吃
狗在看家
----------------------
年龄为36岁的老王养了一只黄颜色的9岁的猫
9岁的黄颜色的猫眯着眼睛侧着头吃鱼

4 包、final关键字

4.1 什么是包?

包就是文件夹。用来管理各种不同功能的Java类,方便后期代码维护。

包名的规则:公司域名反写+包的作用,需要全部英文小写,见名知意。

全类名:包名+类名

使用其他类的规则:

(1)、使用同一个包中的类时,不需要导包。

(2)、使用java.lang包中的类时,不需要导包。

(3)、其他情况都需要导包。

(4)、如果同时使用两个包中的同名类,需要用全类名。

实践案例如下:

package DaoBaoLianXi01;public class Student {private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}
package DaoBaoLianXi02;public class Teacher {private String name;private int age;public Teacher() {}public Teacher(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}
package DaoBaoLianXi03;public class Teacher {private String name;private int age;public Teacher() {}public Teacher(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}
package DaoBaoLianXi01;import DaoBaoLianXi02.Teacher;public class Test {public static void main(String[] args) {//创建对象,验证使用同一个包中的类时,不需要导包Student s = new Student();s.setName("张三");s.setAge(23);System.out.println(s.getName()+","+s.getAge());//验证使用java.lang包中的类时,不需要导包。(String属于java.lang包中的字符串对象)String str = "abc";System.out.println(str);//验证 其他情况下都需要导包//调用了DaoBaoLianXi02里的Teacher类,所以第三行的时候导包了,不然会报错//导包时的代码 import DaoBaoLianXi02.Teacher;//Teacher t = new Teacher();//验证 如果同时使用两个包中的同名类,需要全类名//验证方式:新建两个包DaoBaoLianXi02和DaoBaoLianXi03,在这两个包里面分别定义一个Teacher类//当同时使用两个包中的同名类,需要全类名,不然会报错。DaoBaoLianXi02.Teacher t2 = new DaoBaoLianXi02.Teacher();t2.setName("王二");       t2.setAge(12);System.out.println(t2.getName()+","+t2.getAge());DaoBaoLianXi03.Teacher t3 = new DaoBaoLianXi03.Teacher();t3.setName("三三三");     t3.setAge(18);System.out.println(t3.getName()+","+t3.getAge());}
}

4.2 final关键字

被final修饰后,就不能再改变。final可以修饰方法、类、变量。

(1)修饰方法时:表明该方法是最终方法,不能被重写。(一般用于设置某种不希望被改变的规则。)

(2)修饰类时:表明该类是最终类,不能被继承。

(3)修饰变量时:被修饰的变量叫做常量,只能被赋值一次,且不能被修改。(可以定义和赋值分开写)

修饰方法:
public final void shout(){}修饰类:
final class Animal{}修饰变量:
final int a = 10;    //变量被final修饰的同时必须直接赋值,否则会报错。比如以下情况会报错:
final int b;
b = 4;

细节验证案例如下:

package finalLianXi;public class Student {private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}
package finalLianXi;public class Test {public static void main(String[] args) {/*** final 修改基本数据类型:记录的值不能发生改变。* final 修饰引用数据类型:记录的地址值不能发生改变,内部的属性值还是可以改变的。*///核心:常量记录的数据是不会发生改变的。(下面的s和Arr是引用变量,记录的都是地址值)final double PI = 3.14; //基本数据类型//创建对象final Student s = new Student("张三",23); //s为引用数据对象// s = new Student();   会报错,因为这行代码运行后改变了s的地址值s.setName("李四");    //对属性值name进行修改s.setAge(24);   //对属性值age进行修改System.out.println(s.getName()+","+s.getAge());     //李四,24//数组final int[] Arr ={1,2,3,4,5};//Arr = new int[10];  会报错,因为这行代码运行后改变了Arr的地址值Arr[0] = 10;Arr[1] = 20;//遍历数组for (int i = 0; i < Arr.length; i++) {System.out.print(Arr[i]+"\t");  //10 20  3   4   5}}
}

final练习案例:常量的练习

要求:将学生管理系统中用户的操作改写为常量的形式。

思路:把学生管理系统中的switch结构中的选项换成英语单词(英文单词提前被final修饰并赋值),从而增加了代码的可读性。

说明:途中的图片均为黑马程序员视频截图,来源于B站视频

黑马程序员Java零基础视频教程(2022最新Java)B站视频学习笔记-Day13-面向对象进阶01相关推荐

  1. 黑马程序员Java零基础视频教程(2022最新Java)B站视频学习笔记-Day10-字符串

    1.API和API帮助文档 API:应用程序接口. 简单理解:API就是别人已经写好的东西,我们不需要自己编写,直接使用即可. JavaAPI:指的就是JDK中提供的各种功能的Java类.这些类将底层 ...

  2. 黑马程序员Java零基础视频教程(2022最新Java)B站视频学习笔记-Day15-阶段项目(拼图小游戏)(上篇)

    1.主界面分析 1.练习:创建主界面1 到IDEA中创建一个宽603像素,高680像素的游戏主界面 到IDEA中创建一个宽488像素,高430像素的登录界面 到IDEA中创建一个宽488像素,高500 ...

  3. 黑马程序员Java零基础视频教程(2022最新Java)B站视频学习笔记-Day12-学生管理系统

    基础版本: 需求:采取控制台的方式去书写学生管理系统. 分析: (1).初始菜单: (2).学生类: 属性:id.姓名.年龄.家庭住址. (3).添加功能: 键盘录入每一个学生信息并添加,满足以下要求 ...

  4. 黑马程序员Java零基础视频教程(2022最新Java)B站视频学习笔记-Day14-面向对象进阶02

    1.权限修饰符和代码块 1.1 权限修饰符 权限修饰符:是用来控制一个成员能够被访问的范围的. 可以修饰:成员变量.方法.构造方法.内部类. 巧计举例: private--------私有的----- ...

  5. 黑马程序员Java零基础视频教程(2022最新Java)B站视频学习笔记-Day7-综合练习

    1.卖飞机票 需求:机票价格按照淡季旺季.头等舱和经济舱收费.输入机票原价.月份和头等舱或者经济舱. 按照如下规则进行计算机票价格:旺季(5-10月)头等舱9折,经济舱8.5折:淡季(11月到来年4月 ...

  6. 黑马程序员Java零基础视频教程(2022最新Java)B站视频学习笔记-Day4-判断和循环

    1.顺序结构 顺序结构语句是Java程序默认的执行流程,按照代码的先后顺序,从上到下依次执行. 2.分支结构 1.if语句 (1).if语句的第一种格式,格式如下: if (关系表达式){语句体; } ...

  7. 黑马程序员Java零基础视频教程(2022最新Java)B站视频学习笔记-Day11-ArrayList集合

    1.集合的基本应用 数组的长度是固定的,集合的长度是可变的,集合具有自动扩容的功能. 数组可以存基本数据类型和引用数据类型,集合只能存储引用数据类型,基本数据类型只有设置成包装类才能存储在集合当中. ...

  8. 黑马程序员Java零基础视频教程_下部(P52-P134)

    黑马程序员Java零基础视频教程_下部(P52-P134) 1. 异常 1.1 异常体系介绍 1.2 编译时异常和运行时异常 1.3 异常在代码中的两个作用 1.4 JVM虚拟机默认处理异常的方式 1 ...

  9. 黑马程序员Java零基础视频教程_下部(P135-P200)

    黑马程序员Java零基础视频教程_下部(P135-P200) 1 多线程 1.1 什么是多线程? 1.2 多线程的并发与并行 1.3 多线程的实现方式 1.3.1 继承Thread类的方式进行实现 1 ...

  10. 黑马程序员Java零基础视频教程_上部(P1-P80)

    黑马程序员Java零基础视频教程_上部(P1-P80) 1. Java入门 1.1 Java学习介绍 1.2 Java人机交互 1.2.1 常用CMD命令 2. Java基础学习 2.1 Java入门 ...

最新文章

  1. 脑植入芯片实现脑机交互,脑神经链会如星链般放大马斯克的光环吗
  2. ICMP协议抓包分析-wireshark
  3. 硬盘安装Linux救援系统,硬盘安装linux系统
  4. html5实现3d翻页效果,利用css3 3d transform制作超逼真翻书效果
  5. try-catch捕获异常信息后Spring事务失效处理方法
  6. 阿里云数据中台训练营第一期圆满落幕
  7. 知乎高赞:如果你是一个 Java 面试官,你会问哪些问题....
  8. 计算机网络路由器方面的论文,简析计算机网络问题中路由器故障的论文
  9. python手机版下载-QPython下载
  10. form 表单序列化 serialize
  11. 浙大python判断两个字符串是否为变位词_算法2----------变位词
  12. postgresql表空间迁移
  13. 数字版权管理 (DRM) 续
  14. 百度离线地图服务器搭建
  15. 论文中的图目录与表目录
  16. r语言赋值为na_如何将R数据中的NA值替换为0?
  17. Mac虚拟机实现ios UI自动化教程-最新版本(MacOS 12.1,ios15.1)
  18. Nowcoder. 链表的回文结构
  19. python批量添加qq好友_python实现QQ批量登录功能
  20. 无线Mesh网构建无线城市

热门文章

  1. 11尺寸长宽 iphone_2019新发布iPhone 11、iPhone 11 Pro、iPhone 11 Pro Max尺寸规格对比
  2. 详解电源反接使用MOS管保护电路原理及其优势
  3. python录入数据,python处理写入数据教学教程
  4. 2023年天津仁爱学院专升本考试考务费网上缴费的通知
  5. 十个数字内的最小绝对值
  6. 解决 DevExpress21 控件不在工具箱显示问题
  7. 学员管理系统(完整版附带源码)
  8. 哈希算法(哈希函数)基本
  9. 1080p和1080i
  10. org.apache.hadoop.hbase.ipc.ServerNotRunningYetException: Server is not runn Hbase shell 无法执行命令