- 多态:父类型引用指向子类型对象
- 多态注意事项:
- 子类对象可以直接赋给父类引用,但父类对象在任何情况下都不可以直接赋给子类引用,因为子类是父类的一种,但父类不是子类的一种,或者说 子类可以当做父类看待,但父类不可以当做子类看待 , 打个比喻,狗可以当做动物看待,但动物不可以当做狗来看待;
- 通过父类引用只能访问子类对象从父类继承过来的成员,不能访问子类对象所特有的成员
- 上面说父类引用永远不可能直接赋给子类引用,有一个特殊情况,只有在父类引用本身指向的就是一个子类对象时,才可以把父类引用强制转化为子类引用,其他情况下不允许把父类引用强制转化为子类引用,否则运行时会出错
- 代码演示:
public class Test
{
public static void main(String[] args){
A aa=new A();
B bb=new B();
//bb=aa;//error
bb=(B)aa;//编译没有错误,但运行时出错
A aa2=new B();
bb=aa2;//error 永远不可以把父类引用直接赋给子类引用
bb=(B)aa2; //OK 因为aa2本身指向的就是一个B类对象(子类对象)
}
}
class A
{
}
class B extends A
{
}
错误原因:
- 多态在实际开发中的作用:降低程序的耦合度,提高程序的扩展力
- 抽象类与抽象方法:
public class Poly {
public static void main(String[] args) {
}
}
//有抽象方法的类一定是抽象类
abstract class B
{
public abstract void f();//没有方法体
}
//抽象类不一定有抽象方法
abstract class C
{
public void g()
{
}
}
- 抽象类的由来:利用抽象类是为了更好的对类加以分类,就像人类不但给各种具体植物取了名字,还发明了“植物”这个抽象的词对所有具体植物进行归类一样
- Java用来模拟现实世界,所以也存在抽象类,抽象类通常用来作为一个类族的最顶层的父类,用最底层的类表示现实中的具体事物,用最顶层的类表示该类族所有事物的共性,就好像生物分为动物和植物,动物又分为高级动物和低级动物等等,通常最上面的若干层类都是抽象的。
package com.ittanya.demo1;
public class AbsPoly{
public static void main(String[] args) {
//C cc=new C();//错误
B bb = new B();
bb.f();
C cc;//可以定义一个抽象类的引用,但是不可以定义一个抽象类的对象
cc = bb;
bb.f();
}
}
abstract class C
{
abstract public void f();
//public abstract void g();//报错
}
class B extends C
{
public void f(){
System.out.println("BBBB");
}
}
几种错误**:**
- Final关键字的使用:
- 修饰整个类:
- Final修饰类中的若干属性:
package com.ittanya.demo1;
public class 草稿 {
public static void main(String[] args) {
}
}
class B
{
final public int i;//常变量=const
//但不能同时有两个赋值语句
public B()//在构造方法中赋值,不报错
{
i=99;
}
/*public void f() 报错
{
i=22;
}*/
}
注意:默认值不算真正的赋值
3. Final修饰类中的若干个方法:
- 接口:
- 接口的作用:
package com.ittanya.demo1;
interface It{
//接口中定义的属性的值在实现类中不能被更改
//接口的属性是public static final 类型
public static final int i=20;//冗余
public abstract void f();//冗余
}
//接口中是不可以定义构造函数的
interface It1{
int i=20; //不能改为 int i;
void f();
}
//接口可以多重继承,即一个接口可以有多个父接口,但是一个类只能有一个父类
interface It2 extends It,It1{
}
//implements不能改为extends 因为类可以继承类,但类不能继承接口,逻辑意义不通,但类可以实现接口
class T implements It1{
public T(int j){
//this.i=j;//无法将值赋给 final 变量 'i'
//接口It中的属性i是public static final 类型
j=20;
System.out.println(j);
System.out.println("父类");
}
public void f(){
System.out.println(i);
}
}
//一个类可以在继承一个父类的同时实现一个或多个接口,但extends关键字必须在前
class T1 extends T implements It,It1{
public T1(int j) {
super(10);
System.out.println("子类");
}
}
class 接口 {
public static void main(String[] args) {
T tt=new T(30);
tt.f();
}
}
运行结果:
package com.ittanya.demo1;
interface It{
void f();
}
abstract class T implements It{
public void f(){
System.out.println("AAAA");
}
}
class 接口 {
public static void main(String[] args) {
int i;
It it;
It it1=new It() {
@Override
public void f() {
System.out.println("TTTT");
}
};
it1.f();
}
}
运行结果:
- 接口与抽象类区别:
- 接口中的方法不允许有方法体,但抽象类却允许
- Java类不允许多承,接口却允许多继承
(接口可以实现多继承,即一个接口可以有多个父类
但Java类只允许单继承,即一个类只能有一个父类)
- 杂七杂八:
3. Animala5=new Cat(); //底层对象是一只猫
// 分析这个程序能否编译和运行呢?
分析程序一定要分析编译阶段的静态绑定和运行阶段的动态绑定,
只有编译通过的代码才能运行。没有编译,根本轮不到运行。
// 错误:找不到符号
// why???
因为编译器只知道a5的类型是Animal,去Animal,class文件中找catchMouse()方法
//结果没有找到,所以静态绑定失败,编译报错。无法运行。(语法不合法)
a5.catchMouse :
假设代码写到了这里,非要调用catchMouse()方法怎么办?
//这个时候就必须使用”向下转型”了。(强制类型转换)
//以下这行代码头啥没报错????
//因为a5是Animal类型,转成Cat,Animal和Cat之间存在继承关系。所以没报错
Cat x=(Cat)a5.x.catchMouse();
//猫正在抓老鼠!! ! !
-
类到对象是实例化。对象到类是抽象。
-
抽象类:
1、什么是抽象类?
类和类之间具有其同特征形成的就是抽象类,
将这些共同特征提取出来,形成的类就是抽象类,类本身是不在在的,所以抽象类无法创建对象(无法实例化)。2、抽象类属于什么类型?
抽象类也属于引用教据类型。3、抽象类怎么定义?
语法: [修饰符列表] abstract class 类{类体:
}
4、抽象类是无法实例化的,无法创建对象的,所以抽象类是用来被子类继承的。5、final和abstract不能联合使用,这两个关键字是对立的。
6、抽象类的子类可以是抽象类。也可以是非抽象类。
7、抽象类虽然无法实例化,但是抽象类有构造方法,这个构造方法是供子类使用的。
8、抽象类关联到一个概念:抽象方法。
什么是抽象方法呢?
抽象方法表示没有实现的方法,没有方法体的方法。例如:
public abstract void dosome();抽象方法特点是:
特点1:没有方法体,以分号结尾。
特点2:前面修饰符列表中有abstract关键字。9、抽象类中不一定有抽象方法,抽象方法必须出现在抽象类中
10、重要结论(五颗星):
一个非抽象的类继承抽象类,必须将抽象类中的抽象方法实现了,这是java语法上强行规定的,必须的,不然编译器就报错了
这里的覆盖或者说重写,也可以叫做实现。(对抽象的实现) -
面试题(判断题): java语言中凡是没有方法体的方法都是抽象方法
错误。
object类中就有很多方法都没有方法体,都是以”;"结尾的,但他们都不是抽象方法,例如:
public native int hashCode() ;
这个方法底层调用了c++写的动态链接库程序。前面修饰符列表中没有:abstract。有一个native。表示调用JVM本地程序。 -
代码演示1:
public class AbstractTest02{
public static void main(string[] args){
// 能不能使用多态
// 父类型引用指向子类型对象
Animal a=new Bird();
//向上转型。(自动类型转换)
// 这就是面向抽象编程。
//以后你都是调用的a.xxxx
// a的类型是Animal,Animal是抽象的
// 面向抽象编程,不要面向具体编程,降低程序的耦合度,提高程序的扩展力。这种编程思想符合OCP原则。
//分析以下:
//编译的时候这个move()方法是谁的?
//运行的时候这个move()方法又是谁的?
a.move();
}
}
- 代码演示2:
package com.ittanya.demo1;
abstract class Animal1{
public abstract void move();
}
//子类(非抽象的)
// 错误: Bird不是抽象的,并且未覆盖Anima1中的抽象方法move()
/*
class Bird extends Animal1{
}
*/
class Bird extends Animal1{
public void move(){
System.out.println("鸟儿在飞翔!");
}
}
class Cat1 extends Animal1{
public void move(){
System.out.println("猫在走猫步!");
}
}
// 如果Bird是抽象类的话,那么这个Animal中继承过来的抽象方法也可以不去重写/覆盖/实现
abstract class Bird1 extends Animal1{
}
- final关键字:
1.1、final修饰的类无法继承。
1.2、fina1修饰的方法无法覆益。
1.3、final修饰的变量只能赋一次值。
1.4、final修饰的引用一指向某个对象,则不能再重新指向其它对象,但该引用指向的对象内部的数据是可以修改的。
1.5final修饰的实变量必须手动初始化,不能采用系统默认值。
1.6、fina1修饰的实例变量一般和static联合使用,称为常量,如:
public static final double PI =3.1415926;