1.多态的定义:多态是在继承/实现情况下的一种现象,表现为:对象多态,行为多态。
S和T都继承于P类,S和T都有run()方法,T类是经过方法重写的,
P p1 = new S();
p1.run();
P p2 = new T();
p2.run();
多态的前提:存在继承/实现关系;存在父类引用子类对象;存在方法重写。
public class test {
public static void main(String[] args) {
people p1 = new teacher();//编译看左边,运行看右边
p1.run();
System.out.println(p1.name);//输出为people,这里输出是people是因为teacher和student都继承了people,但是没有重写name属性,所以调用的还是父类的name属性
people p2 = new student();
p2.run();
System.out.println(p2.name);//输出为people
}
}
public class student extends people{
public String name = "student";
@Override
public void run(){
System.out.println("student is running");
}
}
public class teacher extends people {
public String name ="teacher";
@Override
public void run() {
System.out.println("teacher is running");
}
}
public class people {
public String name = "people";
public void run() {
System.out.println("people is running");
}
}
2.使用多态的好处
(1)在多态模式下,右边对象是解耦合的,更便于扩展和维护。
使用上边的例子,就是可以把new student改成new teacher 。
(2)定义方法时,使用父类类型的形参,可以接受一切子类对象,扩展性更强,更便利。
public static void go(people p){
//使用people既可以接受student也可以接受teacher
}
3.多态下不能使用子类的独有功能。
示例
public class test {
public static void main(String[] args) {
people p1 = new teacher();//编译看左边,运行看右边
p1.run();
System.out.println(p1.name);//输出为people,这里输出是people是因为teacher和student都继承了people,但是没有重写name属性,所以调用的还是父类的name属性
people p2 = new student();
p2.run();
System.out.println(p2.name);//输出为people
//p2.study();//报错,多态下存在的问题,student和teacher都继承了people,但是student没有重写study方法,所以调用的还是父类的study方法
}
public static void go(people p){
//使用people既可以接受student也可以接受teacher
}
}
public class student extends people{
public String name = "student";
@Override
public void run(){
System.out.println("student is running");
}
public void study(){
System.out.println("student is studying");
}
}
解决方法:类型转换
(1)自动类型转换:父类 变量名 = new 子类(); people p = new teacher();
(2)强制类型转换:子类 变量名 = (子类)父类变量; teacher t = (teacher)p;
存在继承关系就可以在编译阶段强制类型转换,运行时,如果发现对象的真实类型与强转后的类型不同,就会报类型转换异常(ClassCastExcaption)。
student s1 = (student) p2;
s1.study();
但是如果按照下面第十三行写法会报错,因为P2时student对象,两个子类不能互相转。
public class test {
public static void main(String[] args) {
people p1 = new teacher();//编译看左边,运行看右边
p1.run();
System.out.println(p1.name);//输出为people,这里输出是people是因为teacher和student都继承了people,但是没有重写name属性,所以调用的还是父类的name属性
people p2 = new student();
p2.run();
System.out.println(p2.name);//输出为people
//p2.study();//报错,多态下存在的问题,student和teacher都继承了people,但是student没有重写study方法,所以调用的还是父类的study方法
student s1 = (student) p2;
s1.study();
teacher t1 = (teacher) p2;//报错
}
public static void go(people p){
//使用people既可以接受student也可以接受teacher
}
}
解决方法:instanceof关键字
if(p2 instanceof student) {//使用instanceof关键字判断是否是student类型
student s2 = (student) p2;
s2.study();
}else{
teacher t2 = (teacher) p2;
}
public class test {
public static void main(String[] args) {
people p1 = new teacher();//编译看左边,运行看右边
p1.run();
System.out.println(p1.name);//输出为people,这里输出是people是因为teacher和student都继承了people,但是没有重写name属性,所以调用的还是父类的name属性
people p2 = new student();
p2.run();
System.out.println(p2.name);//输出为people
//p2.study();//报错,多态下存在的问题,student和teacher都继承了people,但是student没有重写study方法,所以调用的还是父类的study方法
student s1 = (student) p2;
s1.study();
// if(p2 instanceof student) {//使用instanceof关键字判断是否是student类型
// student s2 = (student) p2;
// s2.study();
// }else{
// teacher t2 = (teacher) p2;
// }
// // teacher t1 = (teacher) p2;
System.out.println("--------------");
student s2 = (student) p2;
go(s2);
teacher t2 = (teacher) p1;
go(t2);
}
public static void go(people p){
//使用people既可以接受student也可以接受teacher
p.run();
if(p instanceof student){
student s = (student) p;
s.study();
}else{
teacher t = (teacher) p;
t.teach();
}
}
}
上面代码20行往下运行结果:
4.final关键字
package com.lzk.test;
import java.util.Random;
import java.util.Scanner;
public class test {
public static final String str = "hello world"; //这里一定要赋值,而且下面不能再改
public static void main(String[] args) {
final int a ;
a = 10;
// a = 11; // 报错,不能修改final变量
}
public static void test1(final int b) {//b不能修改
//b = 20; // 报错,不能修改final变量
}
final int[] arr = {1,2,3};
// arr = null;// 报错,数组地址不能修改
// arr[1] = 10; // 报错,数组不能修改
final class A{
}
class C {
public final void test() {
}
}
class B extends C {
// @Override 报错,因为父类final修饰了方法,子类不能重写
// public void test(){
// }
}
}
public class ContantTest {
public static final String SCHOOL_NAME = "Beijing University";//常量名一般使用大写英文字母加下划线
}
5.抽象类:abstract
public class test {
public static void main(String[] args) {
A a = new A();//报错
a.run();
}
}
public abstract class A {// 2.定义一个抽象类A,带abstract关键字
public abstract void run();// 1.定义一个抽象方法,没有大括号,class A要带abstract关键字
public A(){
}
}
6.抽象类的好处
特点是在调用时必须进行重写。
7.抽象类的应用场景
解决方法中的重复代码。
public class test {
public static void main(String[] args) {
teacher t = new teacher();
t.write();
student s = new student();
s.write();
}
}
public abstract class people {
public void final write(){//加上final方法防止被子类重写
System.out.println("writing");
System.out.println("writing1");
System.out.println(writemain());
System.out.println("writing2");
}
public abstract String writemain();
}
public class student extends people{
@Override
public String writemain() {
return "I write xxx.";
}
}
public class teacher extends people {
@Override
public String writemain() {
return "I write essays.";
}
}
将中间不重复的地方换成抽象类重写代码。