抽象类:
抽象:笼统,模糊,看不懂!不具体。
特点:
1,方法只有声明没有实现时,该方法就是抽象方法,需要被abstract修饰。
抽象方法必须定义在抽象类中。该类必须也被abstract修饰。
2,抽象类不可以被实例化。为什么?因为调用抽象方法没意义。
3,抽象类必须有其子类覆盖了所有的抽象方法后,该子类才可以实例化。
否则,这个子类还是抽象类。
1,抽象类中有构造函数吗?
有,用于给子类对象进行初始化。
2,抽象类可以不定义抽象方法吗?
可以的。 但是很少见,目的就是不让该类创建对象。AWT的适配器对象就是这种类。
通常这个类中的方法有方法体,但是却没有内容。
3,抽象关键字不可以和那些关键字共存?
private 不行
static 不行
final 不行
4,抽象类和一般类的异同点。
相同点:
抽象类和一般类都是用来描述事物的,都在内部定了成员。
不同:
1,一般类有足够的信息描述事物。
抽象类描述事物的信息有可能不足。
2,一般类中不能定义抽象方法,只能定非抽象方法。
抽象类中可定义抽象方法,同时也可以定义非抽象方法。
3,一般类可以被实例化。
抽象类不可以被实例化。
5,抽象类一定是个父类吗?
是的。因为需要子类覆盖其方法后才可以对子类实例化。
abstract class AbsDemo
{
abstract void show1();
abstract void show2();
}
当一个抽象类中的方法都是抽象的时候,这时可以将该抽象类用
另一种形式定义和表示,就是 接口 interface。
//定义接口使用的关键字不是class,是interface.
对于接口当中常见的成员:而且这些成员都有固定的修饰符。
1,全局常量: public static final (修饰符不写会自动补全)
2,抽象方法。public abstract
由此得出结论,接口中的成员都是公共的权限.
interface Demo
{
public static final int NUM = 4;
public abstract void show1();
public abstract void show2();
}
//类与类之间是继承关系,类与接口直接是实现关系。
接口不可以实例化。
只能由实现了接口的子类并覆盖了接口中所有的抽象方法后,该子类才可以实例化。
否则,这个子类就是一个抽象类。
class DemoImpl implements /*实现*/Demo
{
public void show1()
{}
public void show2()
{
}
}
在java中不直接支持多继承,因为会出现调用的不确定性。
所以java将多继承机制进行改良,在java中变成了多实现。
一个类可以实现多个接口。 接口的出现避免了单继承的局限性。
抽象类和接口的异同点:
相同点:
都是不断向上抽取而来的。
不同点:
1,抽象类需要被继承,而且只能单继承。
接口需要被实现,而且可以多实现。
2,抽象类中可以定义抽象方法和非抽象方法,子类继承后,可以直接使用非抽象方法。
接口中只能定义抽象方法,必须由子类去实现。
3,抽象类的继承,是is a关系,在定义该体系的基本共性内容。
接口的实现是 like a 关系,在定义体系额外功能。
例子:犬按功能分:有导盲犬,搜爆犬。
abstract class 犬 //基本功能
{
abstract void 吼叫();
}
interface 导盲 //额外功能
{
abstract void 导盲();
}
class 导盲犬 extends 犬 implements 导盲
{
public void 吼叫()
{
}
public void 导盲(){}
}
对象的多态性。
class 动物
{}
class 猫 extends 动物
{}
class 狗 extends 动物
{}
猫 x = new 猫();
动物 x = new 猫();//一个对象,两种形态。
猫这类事物即具备者猫的形态,又具备着动物的形态。
这就是对象的多态性。
简单说:就是一个对象对应着不同类型.
多态在代码中的体现:
父类或者接口的引用指向其子类的对象。
多态的好处:
提高了代码的扩展性,前期定义的代码可以使用后期的内容。
多态的弊端:
前期定义的内容不能使用(调用)后期子类的特有内容。
多态的前提:
1,必须有关系,继承,实现。
2,要有覆盖。
毕老师和毕姥爷的故事。
class 毕姥爷
{
void 讲课()
{
System.out.println("管理");
}
void 钓鱼()
{
System.out.println("钓鱼");
}
}
class 毕老师 extends 毕姥爷
{
void 讲课()
{
System.out.println("Java");
}
void 看电影()
{
System.out.println("看电影");
}
}
class DuoTaiDemo2
{
public static void main(String[] args)
{
// 毕老师 x = new 毕老师();
// x.讲课();
// x.看电影();
毕姥爷 x = new 毕老师();//多态,自动类型提升,老师对象提升了姥爷类型。但是只能访问毕姥爷的方法(外部看到的是毕姥爷(本身是毕老师),若毕姥爷和毕老师有方法一样,使用的是毕老师的方法),无法使用毕老师特有的方法。
//作用就是限制对特有功能的访问。
//专业讲:向上转型。将子类型隐藏。就不用使用子类的特有方法。
x.讲课();
x.钓鱼();
毕老师 y = (毕老师)x;//如果想用毕老师的特有功能,你可以将该对象进行向下转型。
//向下转型的目的是为了使用子类中的特有方法。
// 注意:对于转型,自始自终都是子类对象在做着类型的变化。
y.看电影();
}
}
//a instanceof People//instanceof:用于判断对象的具体类型。只能用于引用数据类型判断 //通常在向下转型前用于健壮性的判断。
多态时
成员的特点:
1,成员变量。
编译时:参考引用型变量所属的类中的是否有调用的成员变量,有,编译通过,没有,编译失败。
运行时:参考引用型变量所属的类中的是否有调用的成员变量,并运行该所属类中的成员变量。
简单说:编译和运行都参考等号的左边。
2,成员函数(非静态)。
编译时:参考引用型变量所属的类中的是否有调用的函数。有,编译通过,没有,编译失败。
运行时:参考的是对象所属的类中是否有调用的函数。
简单说:编译看左边,运行看右边。
因为成员函数存在覆盖特性。
3,静态函数。
编译时:参考引用型变量所属的类中的是否有调用的静态方法。
运行时:参考引用型变量所属的类中的是否有调用的静态方法。
简单说,编译和运行都看左边。
其实对于静态方法,是不需要对象的。直接用类名调用即可。
内部类访问特点:
1,内部类可以直接访问外部类中的成员。
为什么内部类能直接访问外部类中成员呢?
那是因为内部类持有了外部类的引用。 外部类名.this
2,外部类要访问内部类,必须建立内部类的对象。
一般用于类的设计。
分析事物时,发现该事物描述中还有事物,而且这个事物还在访问被描述事物的内容。
这时就是还有的事物定义成内部类来描述。
class InnerClassDemo
{
public static void main(String[] args)
{
// Outer out = new Outer();
// out.method();
//直接访问外部类中的内部类中的成员。
// Outer.Inner in = new Outer().new Inner();
// in.show();
//如果内部类是静态的。 相当于一个外部类
// Outer.Inner in = new Outer.Inner();
// in.show();
//static void function()//如果内部类中定义了静态成员,该内部类也必须是静态的。
//如果内部类是静态的,成员也得是静态的。
// Outer.Inner.function();
}
}
内部类可以存放在局部位置上。
内部类在局部位置上只能访问局部中被final修饰的局部变量。
class Outer
{
int num = 3;
Object method()
{
final int x = 9;
class Inner
{
public String toString()
{
return "show ..."+x;//内部类在局部位置上只能访问局部中被final修饰的局部变量。
}
}
Object in = new Inner();
return in;//0x0045
// in.show();
}
}
class InnerClassDemo3
{
public static void main(String[] args)
{
Outer out = new Outer();
Object obj = out.method();
System.out.println(obj);
}
}
/*
class Fu extends Object
{}
class zi extends Fu
{}
Fu f = new zi();
Object o = new Fu();
匿名内部类。就是内部类的简写格式。
必须有前提:
内部类必须继承或者实现一个外部类或者接口。
匿名内部类:其实就是一个匿名子类对象。
格式:new 父类or接口(){子类内容}
通常的使用场景之一:
当函数参数是接口类型时,而且接口中的方法不超过三个。
可以用匿名内部类作为实际参数进行传递
class Outer
{
void method()
{
/*new Object()
{
public void show()
{
System.out.println("show run");
}
}.show()//运行通过;*/
Object obj = new Object()
{
public void show()
{
System.out.println("show run");
}
};
obj.show();//因为匿名内部类这个子类对象被向上转型为了Object类型。
//这样就不能在使用子类特有的方法了。obj没有show方法
}
}
class InnerClassDemo6
{
public static void main(String[] args)
{
new Outer().method();
}
}
实例化对象运行的顺序::首先执行构造函数中默认的super()父类初始化父类=》然后初始化当前对象=》最后执行构造函数中的代码