多态:
extends继承 implements实现 是多态的前提
【类与类的继承 接口与接口的继承 类与接口之间的实现】
总之,有上下关系是多态的前提
人(父类)----------学生(子类)、员工(子类)
小明是一个学生(学生形态)也是一个人(人类形态)
小明是一个对象,既有学生形态也有人类形态,一个对象有多个形态,这就是对象的多态性
多态格式:
父类名称 对象名 = new 子类名称();
接口名称 对象名 = new 实现类名称();
public class Fu {
public void metod(){
System.out.println("父类方法");
}
public void metod1(){
System.out.println("父类特有方法");
}
}
public class Zi extends Fu {
public void metod(){
System.out.println("子类方法");
}
}
public class Demo {
public static void main(String[] args) {
Fu obj = new Zi(); //多态
obj.metod();
obj.metod1();
}
}
===============================================
多态访问成员变量
1.直接方法,对于成员变量的访问,看等号左边是谁,就到那个类里去找
2.间接方法,对于成员方法,看属于谁,就先到那个类里找,没有则向上找。
public class Fu {
int num=10;
public void NUM(){
System.out.println(num);
}
}
public class Zi extends Fu{
int num=20;
int ages=200;
}
public class Demo {
public static void main(String[] args) {
Fu obj = new Zi();
System.out.println(obj.num);//直接去找
//System.out.println(obj.ages); 错误,先到Fu类去找,没有则想上找,不会向下(Zi)找
obj.NUM(); //间接去找
}
}
====================================================
多态中成员方法的使用方法
- 成员变量:编译看左边,运行看左边
成员方法:编译看作左边,运行看右边
public class Fu {
public void methodFu(){
System.out.println("父类方法");
}
public void method(){
System.out.println("fu 10");
}
}
public class Zi extends Fu{
public void methodZi(){
System.out.println("子类方法");
}
public void method(){
System.out.println("子 20");
}
}
public class Demo {
public static void main(String[] args) {
Fu obj = new Zi();
obj.methodFu(); //父类方法//先看左边是Fu,先到Fu类找,有这个方法,再到右边Zi类运行,发现没有,向上找到Fu类,运行此方法
obj.method();//20// 先看到左边是Fu,先到Fu类去找,有这个方法,再到右边Zi类运行,发现有这个方法,直接运行
//obj.methodZi(); //看到左边是Fu,先到左边Fu类去找,没有这个方法,就不到右边子类去找了
}
}
======================================================================================
多态的好处
员工(父类)work();//抽象方法
extends或者implements
zilei :讲师 work(jiangke); 助教 work(fudao);
不是用多态:
Teacher one = new teacher();
one.work();//讲课
Assistant two = new Assistent();
two.work();//辅导
多态:
Employee one = new Teacher();
one.work();
Employee two = new Assistant();
two.work();
好处:无论右边切换成哪个子类对象,等号左边调用方法都不变
对象向上转型
1.对象向上转型就是多态写法
格式: 父类名称 对象名 = new 子类名称();
含义:右侧创建一个子类对象,把它当做父类来看待
Animal animal = new cat();
注意:向上转型一定是安全的,从小范围转到了大范围.
================================================
对象向下转型 其实就是一个还原动作
问题:向上转型一定是正确的,但是也有一个弊端
对象一旦向上转型为父类那么无法调用子类原来特有的内容
解决方案:向下转型
格式:子类名称 对象名 = (子类名称)父类对象;
含义:将父类对象,【还原】成本来的子类对象
Animal animal = new Cat();//本来是猫,向上转型成动物
Cat cat = (Cat) animal;//本来是猫,向上转型成动物,还原回来成为本来的猫
注意事项:
1.必须保证对象本来创建的时候,是猫,才能向下转型成猫
2.如果对象创建的时候本来不是猫,现在非要向下转型为猫,就会报错
public abstract class Animal { //父类定义成为抽象类,用abstract修饰
public abstract void eat(); //父类中的抽象方法
}
public class Cat extends Animal{
public void eat(){
System.out.println("猫吃鱼");
}
public void play(){
System.out.println("猫抓老鼠");//猫特有的
}
}
public class Gog extends Animal{
public void eat(){
System.out.println("狗吃SHIT");
}
public void play1(){
System.out.println("gouzi");
}
}
public class Demo {
public static void main(String[] args) {
Animal animal = new Cat();
animal.eat(); new的是猫类
//animal.play();
Cat cat = (Cat)animal; //强制转
cat.play();
//Gog dog = (Gog) animal; //编译不会报错,运行会报错,转错啦
//dog.play1();
}
}
=============================================
用instanceof关键字进行判断
public class Demo {
public static void main(String[] args) {
Animal animal = new Cat();
animal.eat();
//animal.play();//错误
Cat cat = (Cat)animal;
cat.play();
if(animal instanceof Gog) //返回一个真假值
{
Gog dog = (Gog)animal;
dog.play1();
}
if(animal instanceof Cat)
{
Cat catt = (Cat)animal;
catt.play();
}
//Gog dog = (Gog) animal;
//dog.play1();
}
}
===============
public class Demo {
public static void main(String[] args) {
Animal animal = new Cat();
giveanimal(new Cat());
}
public static void giveanimal(Animal animal){
if(animal instanceof Gog) //返回一个真假值
{
Gog dog = (Gog)animal;
dog.play1();
}
if(animal instanceof Cat)
{
Cat catt = (Cat)animal;
catt.play();
}
}
}
=================================================================
Usb
另一篇博客里有详细的讲解
public interface Usb { //创建Usb接口
public abstract void open(); //构造开机抽象方法
public abstract void close(); //构造关机抽象方法
}
public class Mouse implements Usb { //接口实现类
@Override
public void open() { //实现类引用接口中的抽象方法
System.out.println("打开鼠标");
}
@Override
public void close() { //实现类引用接口中的抽象方法
System.out.println("关闭鼠标");
}
public void play(){ //Mouse的特有方法
System.out.println("点击鼠标");
}
}
public class Key implements Usb{ //接口的实现类
@Override
public void open() { //引用接口的抽象方法
System.out.println("打开键盘");
}
@Override
public void close() { //引用接口的抽象方法
System.out.println("关闭键盘");
}
public void play1(){ //Key实现类的特有方法
System.out.println("键盘输入");
}
}
public class Compute {
public void open(){ //类里的开机方法
System.out.println("打开电脑");
}
public void close(){ //类里的关机方法
System.out.println("关闭电脑");
}
public void UseUsb(Usb usb){ //构造一个使用Usb接口的方法,并接收Usb类型的参数
usb.open(); //谁new的,看谁实现的接口
if(usb instanceof Mouse){ //判断实现类是谁,实现对象的向下转型,并调用实现类中的特有方法
Mouse mouse = (Mouse) usb;
mouse.play();
}
if(usb instanceof Key){
Key key = (Key) usb;
key.play1();
}
usb.close();
}
}
public class Demo {
public static void main(String[] args) {
Compute compute = new Compute();// new一个Compute对象
compute.open(); //电脑开机
Usb usb = new Key(); //左边是接口,右边是实现类。 这也是多态。
compute.UseUsb(usb); //传递Usb类型的参数向compute类里的接收Usb的方法中
compute.UseUsb(new Mouse());
compute.close();
}
}
=================================================================
final关键字
代表最终的、不可改变的
常见四种方法
1.可以用来修饰一个类
2.可以用来修饰一个方法
3.可以用来修饰一个局部变量
4.可以用来修饰一个成员变量
1.当前这个类不能有任何子类(太监类)
public final class 方法名称{
----
}
注意:一个类是final类,那么其中所有成员方法都无法进行覆盖重写
public final class MyClass{
public void method(){
System.out.println("方法执行");
}
}
2.不能被覆盖重写
父类中这个方法被final修饰后,这个方法在子类中不能被覆盖重写
注意:方法来说,abstract关键字和final关键字不能被同时使用
public class Fu {
public final void meth(){
System.out.println("final父类");
}
public void meth1(){
System.out.println("无final父类");
}
}
public class Zi extends Fu {
/* public void meth(){ //错误写法
System.out.println("测试");
}
*/
public void meth1(){
System.out.println("覆盖");
}
}
public class Demo {
public static void main(String[] args) {
Zi obj = new Zi();
obj.meth1();
obj.meth();
}
}
==============================================
3.final修饰局部变量
public class Demo {
public static void main(String[] args) {
int num1=10;
num1=20;
System.out.println(num1);
final int num2=20;
/*num2=30; 错误,用final定义后,不能改变值*/
//正确,只要赋值一次就可以
final int num3;
num3=30;
//对于基本类型来说,不可变的的是变量当中的数据值
//对于引用类型来说,不可改变的是变量当中的地制值
Student stu = new Student("赵丽颖");
System.out.println(stu);//打印的地址,一
System.out.println(stu.getName());
stu = new Student("霍建华");
System.out.println(stu);//打印的地址,与一不同
System.out.println(stu.getName());
final Student stu1 = new Student("高圆圆");
/*stu1=new Student("高圆圆圆圆"); 错误,地址不能改变*/
stu1.setName("高圆圆圆圆");//虽然地址不能改变,但是里面的值可以改变
System.out.println(stu1.getName());
}
}
public class Student {
private String name;
public Student(){
}
public Student(String name){
this.name=name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
==========================================
final修饰成员变量
1.由于成员变量具有默认值,所以用了final之后必须手动赋值,就不会给默认值了
2.对于final成员变量,要么直接赋值,要么通过构造方法进行赋值。二者选其一
3.必须保证类中所有重载的构造方法,都最终会对final的成员变量进行赋值。