一,多态
1,多态
一段代码可以运行出多种形态,子类当父类来用,父类变量引用哪种子类对象就调用哪个类的方法;
2,使用多态
在定义函数的形参时,可以定义成父类类型,调用时可以传入所有子类对象;
//练习多态,
class Demo {
public static voidmain(String[] args) {
//创建苹果对象,并调用其方法;
//Apple a = new Apple();
//a.squeeze();
Juicer j= new Juicer() ;
j.run(new Apple());
j.run(new Orange());
}
}
//定义榨汁机类,简化代码;
class Juicer {
public void run(Fruitfruit) {
fruit.squeeze();
}
//public void run(Orangeorange) {
// orange.squeeze();
//}
}
//发现苹果和橘子类中的方法相同,只是打印主体不同,所以把这段代码提取出来,定义一个父类,
//让苹果和橘子类继承父类,这样可以简化juicer类的代码,提高代码的复用性;
abstract class Fruit {
public abstract voidsqueeze() ;
}
class Apple extends Fruit {
public void squeeze() {
System.out.println("榨了一杯苹果汁");
}
}
class Orange extends Fruit {
public void squeeze() {
System.out.println("榨了一杯橘子汁");
}
}
3,多态的体现
父类的引用指向了自己的子类对象。
父类的引用也可以接收自己的子类对象。
4,多态的前提
必须是类与类之间有关系。要么继承,要么实现。
通常还有一个前提:存在覆盖。
5,多态的好处
多态的出现大大的提高程序的扩展性。
6,多态的弊端:
虽然提高了扩展性,但是只能使用父类的引用访问父类中的成员。
在多态中成员函数的特点:
在编译时期:参阅引用型变量所属的类中是否有调用的方法,如果有,编译通过,如果没有编译失败;
在运行时期:参阅对象所属的类中是否有调用的方法;
简单总结就是:成员函数在多态调用时,编译看左边,运行看右边;
在多态中,成员变量的特点:
无论编译和运行,都参考引用型变量所属的类;
在多态中,静态成员函数的特点:
无论编译和运行,都参考引用型变量所属的类;
二,抽象类
1,抽象类
用abstract修饰的类就是抽象类,其中可以定义抽象方法(abstract修饰的方法)
2,什么时候使用抽象类
当多个类拥有相同的方法签名时,我们可以将方法签名相同的方法抽取到父类中定义
子类中签名和方法体都一样的方法,直接在父类中定义,子类继承即可;
子类中签名相同,但方法体不同的方法,在父类中定义抽象方法,子类中对其重写。
3,抽象类的细节
抽象方法不能有方法体;
有抽象方法的类必须声明抽象类;
子类继承抽象类,要么重写所有抽象方法,要么也声明为抽象类;
抽象类不能创建对象;
抽象类可以没有抽象方法;
三,final关键字
1,final定义的类,是最终类,不能别继承 fianl class A {}
2,final定义的方法,是最终方法,不能被重写; final void fun(){}
3,final定义的变量,是最终变量,只能赋值一次;final int X =4;
四,模版设计模式
1,什么时候使用模版设计模式
在编程过程中,如果经常做一段重复的代码,就可以使用模版设计模式,将重复的代码定义在模版中
2,怎么使用模版设计模式
定义抽象类,其中定义一个抽象方法,用来代表每次不同的代码;
定义模版方法,将每次不同的代码写入方法中,不同的代码通过调用抽象方法来实现,模版方法防止子类修改,声明final;
使用模版的时候,继承抽象类,重写抽象方法,写入每次不用的代码;
//练习:计算出运行一段代码需要的时间;
class TemplateDemo1 {
public static voidmain(String[] args) {
//调用方法;
new Test().test();
}
}
abstract class Template {
//2,定义模版方法,将每次不变的方法写在模版中,不同的代码通过调用抽象对象来实现
public final void test(){
long start = System.currentTimeMillis();
dosomething();
long end = System.currentTimeMillis();
System.out.println("使用了"+(end -start)+"毫秒");
}
//1,定义一个抽象方法,用来代表每次不同的代码;
public abstract voiddosomething();
}
//使用模版的时候,继承抽象类,重写抽象方法,写入每次不同的代码;
class Test extends Template {
public voiddosomething() {
for(int x=0; x<1000; x++) {
System.out.print(x);
}
}
}
五,接口
1,接口
是一种特殊的抽象类,只能包含抽象方法;
2,接口和抽象类的区别
抽象类用abstract class定义,而接口用interface定义
抽象类中可以有不抽象的方法,而接口中的方法都是抽象的
抽象类用extends来继承,而接口用implements实现
抽象类中的方法没有默认修饰符,接口中的方法默认是publicabstract修饰的
抽象类中的成员变量没有默认修饰符,而接口中的成员变量是用publicstatic final修饰的
3,什么时候用抽象类,什么时候用接口
能使用接口就不用抽象类,除非必须定义带有方法体的方法;
class InterfaceDemo {
public static voidmain(String[] args) {
//创建person对象;
Person p = new Person();
p.code();
//调用work方法;
work1(p);
work2(p);
}
public static voidwork1(Coder c) {
c.code();
}
public static voidwork2(Student s) {
s.study();
}
}
//创建类实现接口类方法;
class Person implements Coder, Student ,Driver {
public void code() {
System.out.println("编程");
}
public void study() {
System.out.println("学习");
}
public void drive() {
System.out.println("开车");
}
}
//创建接口类
interface Coder {
public abstract voidcode();
}
interface Student {
public abstract voidstudy();
}
interface Driver {
public abstract voiddrive();
}
六,类中的内部类
1,类中的内部类
在类中可以定义一个新的类,称为内部类;
内部类必须先创建外部类对象,才能创建内部类对象;
内部类对象持有外部类对象的一个引用“外部类名.this”,可以使用这个引用访问外部类成员;例如:A.this.name或者A.this.fun();
2,使用内部类
在定义一个类需要访问另一个类的成员时,就可以把当前类定义成另一个类的成员;
3,内部类中不能定义静态成员;
静态的本意就是不用创建对象直接使用,而内部类是需要先创建外部类对象才能使用,这是互相矛盾的;
class InnerClassDemo {
public static voidmain(String[] args) {
A a = new A();
//创建内部类对象,先创建外部类
A.B b = a.new B();
A.B c = new A().new B();
/*上面2段代码都是创建内部类,但是打印结果不同,
区别在于,a.new B()的外部类对象有值,而new A().new B()外部类对象值 为null;
*/
//给变量赋值;
a.name = "aaa";
b.name ="bbb";
//运行方法;
a.fun();
b.fun();
}
}
class A {
String name;
void fun() {
System.out.println("A.fun"+name);
}
//class B就是内部类,A是外部类;B可以访问A的成员;
class B {
String name;
void fun() {
System.out.println("B.fun"+name);
}
}
}
注意:内部类编译后产生的.class文件名字为“外部类名$内部类名.class;
七,静态内部类
1,静态内部类
在定义一个内部类的时候,可以用static修饰;
不用创建外部类对象就可以直接创建内部类对象;例如:A.B b = newA.B();
可以定义静态成员;
2,静态内部类的注意
静态内部类是外部类的一个成员,不能访问外部类的非静态成员;
当内部类在成员位置上,就可以被成员修饰符所修饰。
比如,private:将内部类在外部类中进行封装。
static:内部类就具备static的特性。
当内部类被static修饰后,只能直接访问外部类中的static成员。出现了访问局限。
在外部其他类中,如何直接访问static内部类的非静态成员呢?
new 外部类名.内部类名().方法名();
在外部其他类中,如何直接访问static内部类的静态成员呢?
外部类名.内部类名.方法名();
注意:当内部类中定义了静态成员,该内部类必须是static的。
当外部类中的静态方法访问内部类时,内部类也必须是static的。
八,方法中的内部类
1,方法中的内部类
在一个方法中也能定义内部类,这个内部类只能在当前方法中使用;
2,方法中的内部类注意
方法中的内部类和类中内部类相同,都可以访问外部类成员,访问方式也相同;
方法中的内部类必须先定义再使用;
方法中的内部类不能访问到方法中定义的局部变量,除非这个局部变量被声明为final;
方法中的内部类可以有多个,但是内部类的外部类只能有一个;
方法中的内部类编译后产生的.class文件名字为“外部类名$编号内部类名”.class
class MethodInnerDemo {
public static voidmain(String[] args) {
A a =new A();
a.name ="aa";
a.fun();
}
}
class A {
String name;
void fun() {
System.out.println("A.fun name is ="+name);
//创建方法中的内部类,并在内部类中调用外部类的成员;
class B {
String name ;
void fun() {
System.out.println("B.fun.name="+name+"other.name="+A.this.name);
}
}
//定义内部类
B b = new B();
b.name = "bb";
b.fun();
}
}
九,匿名内部类
1,匿名内部类
是方法中内部类的一种,没有名字,只能使用一次;
2,定义匿名内部类
使用“new 父类名(){类定义}”的方式定义一个匿名内部类,然后使用类创建一个对象;
匿名内部类的class文件名为”外部类名$编号.class;
匿名内部类的写法:p.eat(newStudent() {
public void study() {
System.out.println("学习");
}
});
练习: 补充代码,使用匿名内部类;
class InnerTest {
public static voidmain(String[] args) {
Test.function().method();
/*由Test.function():得出function方法时静态,所以才会被类名直接调用;
function方法后面还带有方法method,Inter接口无法创建对象,说明function方法返回一个Inter的子接口,又因为function方法是静态的,所以创建成员内部类实现接口而且是用static修饰,然后重写method方法;
static class InnerClass implements Inter {
public void method() {
System.out.pritnln("成功");
}
}
*/
}
}
interface Inter {
public abstract voidmethod();
}
class Test{
public static Interfunction() {
//返回匿名内部类;
return new Inter() {
public voidmethod() {
System.out.pritnln("成功");
}
};
}
}
面试题:没有父类或者父级接口,也可以创建匿名内部类;
class Test {
public static void main(String[] args) {
new Object() {
public static void function() {
System.out.println(“因为主函数是静态的,所以匿名内部类也是静态的”);
}
}
}
}