抽象类
什么是抽象类:
只包含抽象的概念,比如只给出动物类,具体是哪个动物不做具体解释,其中包含抽象方法,比如只包含睡觉这个方法,具体什么时间睡,睡多长时间不指明,等到在子类中继承这个抽象类之后再根据子类对象的不同来设定。
抽象方法和抽象类的关系:
抽象方法和抽象类必须使用abstract修饰符来修饰,有抽象方法的类一定是抽象类,但是抽象类中可以不包含抽象方法。
抽象方法和抽象类的格式:
抽象类格式:abstract class 类名{}
抽象方法格式:public abstract void eat();
抽象方法和抽象类的规则
- 抽象类和抽象方法都必须用absrtact来修饰,抽象方法中不能有方法体;
- 抽象类不能被实例化,无法使用new关键字来调用抽象类的构造器创建抽象类的实例。但可以通过子类来实例化它,也是多态的体现。
- 抽象类可以包含成员变量、成员方法、构造器、初始化块、内部类5种成分抽象类的构造器不能用于创建实例,主要是为了用于被其他子类调用。
- 按照多态的方式,有具体的子类实例化抽象类,这也是多态的一种。
- 抽象类必须被子类继承,子类(如果不是抽象类)必须重写抽象类中的全部抽象方法。
- 抽象类中的抽象方法必须重写。
- 一个抽象类不能用final关键字声明。(抽象类必须由子类,final声明的不能有子类。
- 抽象方法只需要声明不需要实现
实例:
Person.class抽象类
public abstract class Person {
//抽象类中可以定义抽象方法也可以定义非抽象方法
public abstract void work();
public abstract void drink();
public void learning(){}
}
Teacher,class
public class Teacher extends Person {
@Override
public void work() {
System.out.println("The work of teacher is teaching");
}
@Override
public void drink() {
System.out.println("Teacher drunk white water");
}
}
Student.class
public class Student extends Person {
@Override
public void work() {
System.out.println("The work of student is learning");
}
@Override
public void drink() {
System.out.println("Student drink jury");
}
}
MyTest.class
public class MyTest {
public static void main(String[] args) {
//在子类中来具体实现抽象方法
Student student = new Student();
student.work();
student.drink();
System.out.println("-------------");
Teacher teacher = new Teacher();
teacher.work();
teacher.drink();
}
}
Teacher和Student都是Person的子类,他们将Person中定义的抽象方法重写,具体实现。
abstract不能用于修饰成员变量,不能用修饰局部变量,不能用于修饰构造器,抽象类中定义的构造器只是普通构造器。
抽象类可以通过多态的方式用子类实例化
// Person person = new Person();
// Error:(15, 25) java: org.westos.practice.Person是抽象的; 无法实例化
Person p=new Teacher();
p.work();
注意事项:
- abstract不能与private共存,他们是矛盾的,abstract要求方法必须被重写,而private则让外界访问不到被修饰的方法和类;
- abstract和final不能共存,final要求被修饰的类不能被继承,修饰的方法不能被重写,这与abstract恰恰相反。
- abstract和static没有意义,被static修饰的方法为内部方法,而被abstratic修饰的方法没有方法体,通过类来调用一个没有方法体的方法会报错。不过他们可以同事修饰内部类。
抽象类的意义
从多个具有相同特征的类中抽象出一个抽象类,以这个抽象类作为其子类的模板,从而避免了子类设计的随意性。
抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础在进行扩展、改造,但子类总体上会大致保留抽象类的行为方式。
模板模式在面向对象的软件中很常用,其原理简单,实现也很简单。
模板模式的简单规则:
- 抽象父类可以只定义需要使用的某些方法,把不能实现的部分方法抽象成抽象方法,留给子类去实现。
- 父类中可能包含需要调用其他系列方法的方法,这些被调用方法既可以由父类实现也可以由其子类实现。父类里提供的方法只是定义一个通用算法,其实现也许并不完全由自身实现,而需要依赖其子类的辅助。
接口
什么是接口:一种特殊的类由全局常量和公共的抽象方法所组成。
定义接口格式:interface 接口名称{
全局常量;
抽象方法;
}
实现接口格式:implements class 类名 implements 接口名{
实现接口中所有抽象方法
}
定义的基本语法:
[修饰符] interface 接口名 extends 父接口1 父接口2 …
{ 零到多个常量定义
零到多个抽象方法定义
零到多个内部类、接口、枚举定义
零到多个默认方法或类方法定义
}
- public可以省略。省略之后按默认修饰符default处理;
- 接口名与类名采用相同命名规则;
- 一个接口可以有多个直接父接口,但接口只能继承接口不能继承类;
接口成员的特点:
- 接口定义的是一种规范,因此接口里不能包含构造器合初始化代码块;
- 接口里的成员变量只能是静态变量,它是与相关的,因此系统会自动为这些成员变量增加static 和final两个修饰符。因此接口里的成员变量只能在定义是指定默认值;
- 接口定义的方法只能是抽象方法、类方法或默认方法,因此如果不能定义默认方法,系统将自动为普通方法增加abstract修饰符。接口里的普通方法不能有方法实现,但类方法、默认方法都必须有方法实现(方法体)。
- 接口的子类可以是抽象类
- 接口和接口之间可以是多继承;
实例:
定义两个接口:
public interface MyInterface1 {
//接口定义的成员变量只能是公共的静态常量
//public static final可以省略,系统会自动为成员变量分配
public static final int num=50;
//定义普通方法只能是public修饰的抽象方法
//public abstract也可以省略
public abstract void jumpHigh();
void fireDtill();
//定义默认方法需要用default修饰
default void print(){
System.out.println("我是接口1中的默认方法");
}
//定义类方法需要用static修饰
static void staticMethod(){
System.out.println("我是接口1中的类方法");
}
}
public interface MyInterface2 {
int num=100;
void swimming();
void playBall();
static void interStaticMethod(){
System.out.println("我是接口2中的类方法");
}
}
接口的继承
接口的继承和类继承不一样,接口完全支持多继承。
定义第三个接口并继承前两个接口
public interface SonInterface extends MyInterface1,MyInterface2 {
int num3=150;
void runing();
}
测试类:
public class MyTest {
public static void main(String[] args) {
System.out.println(SonInterface.num1);
System.out.println(SonInterface.num2);
System.out.println(SonInterface.num3);
}
}
使用接口(在类中实现接口)
接口不能用于创建实例,但接口可以用于声明引用类型变量,当使用接口来声明引用变量类型时,这个引用变量必须引用到其实现类的对象。除此之外接口的主要用途是被实现类实现。
一个类可以实现一个或多个接口,格式:
[修饰符] class 类名 extends 父类 implements 接口1,接口2…接口n{}
这个类必须完全实现这些接口中所定义的全部抽象方法,除非这个类是抽象类,可以保留父接口中的抽象方法不实现。
案例:
定义Animal类,Cat类,Tom类多层继承,在Tom类中实现上面两个接口的抽象方法,调用默认方法和接口中的常量:
Animal.class
public class Animal {
int name;
int age;
public void eat(){
System.out.println("动物吃食");
}
public void sleep(){
System.out.println("动物睡觉");
}
}
Cat.class
public class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫爱吃鱼");
}
@Override
public void sleep() {
System.out.println("猫爱白天睡觉");
}
}
Tom.class
public class Tom extends Cat implements MyInterface1,MyInterface2 {
//实现接口中的方法
@Override
public void jumpHigh() {
System.out.println("Tom会跳高");
}
@Override
public void fireDtill() {
System.out.println("Tom会钻火圈");
}
@Override
public void swimming() {
System.out.println("Tom会游泳");
}
@Override
public void playBall() {
System.out.println("Tom会玩球");
}
//重写父类的方法
@Override
public void eat() {
System.out.println("Tom爱吃带鱼");
}
@Override
public void sleep() {
System.out.println("Tom爱在白天抱着球睡觉");
}
}
测试类
public class MyTest {
public static void main(String[] args) {
Tom tom = new Tom();
//继承父类的方法
tom.eat();
tom.sleep();
//实现接口抽象方法
tom.jumpHigh();
tom.fireDtill();
tom.playBall();
tom.swimming();
//实现接口默认方法,不用重写直接调用
tom.print();
//调用接口中的常量
System.out.println(tom.num1);
System.out.println(tom.num2);
}
}
可以体会到在接口定义了一些杂技,这些杂技并不适合于每个动物,但是现在Tom会这些杂技,就可以实现这方接口中的抽象方法来表示。
Tom对象还可以直接调用接口中的默认方法和常量。
接口和抽象类的区别
相同点:
- 接口和抽象类都不能被实例化,它们都位于继承树的顶端用于被其他类实现和继承;
- 接口和抽象类都可以包含抽象方法,实现接口或继承抽象类的普通子类都必须实现这些抽象方法。
不同点:
- 接口里只能包含抽象方法、静态方法和默认方法,不能为普通方法提供方法实现;抽象类可以包含普通方法。
- 接口只能定义静态常量,不能定义普通成员变量;抽象类中既可以定义普通成员变量又可以定义静态常量;
- 接口里不包含构造器;抽象类里可以包含构造器,抽象类中的构造器并不是用来创建对象,而是让其子类来调用,完成属于抽象类的初始化操作;
- 接口里不能包含初始化块;抽象类中可以;
- 类不能实现多继承;接口可以实现;
最大的差别是在设计目的上:
接口体现的是一种规范,当在一个程序中使用接口时,接口是多个模块间耦合的标准;当在多个程序之间使用接口时,借口就是多个程序之间的通信标准。
抽象类体现的是一种模板式设计。抽象类作为多个子类的抽象父类,可以被当成系统实现过程中的中间产品。这个中间产品已经实现了部分功能,但这个产品却不能当成最终产品,必须有更一步的完善。
This关键字:
- 表示类中的属性
- 可以使用this调用本类中的构造方法
- This表示当前对象
- This之间调用构造方法必须留一个出口(一般都将无参方法作为出口,即就是在无参方法中不要再去调用其它构造方法)
- This最重要的特点就是表示当前对象,java中当前对象就是表示正在调用类中方法的对象
Static关键字:
- 使用static声明(修饰)的属性是所有对象共享的。
- 使用static修饰的可以直接用类名调用。
- 非static声明的方法可以调用static声明的属性或者方法,但是static声明的方法。不可以可以调用非static声明的属性或者方法。
- 静态代码块优先于主方法执行。在类中定义的静态代码快优先于构造块执行,且不管有多少个对象被实例化 静态代码块只执行一次。
代码快:普通代码快 ,构造块,静态代码快,同步代码块。
内部类的唯一好处就是可以方便的访问外部类的私有属性。
final关键字:
- 使用final声明的类不能有子类
- 使用final声明的方法不能被子类重写
- 使用final声明的变量即为常量,常量不可修改
注意:在使用final声明变量时,要求字母全部大写,如PI非常重要。
Public static final double PI = 3.14//全局常量,在整个程序中都不改变
instanceof关键字:判断一个对象是否是一个类的实例。
格式: 对象 instancecof 类 → 返回booolean值。
在进行子类实例化时,其对象属于子类也属于父类,结果都是true.
......在类方法中永远不要去继承一个已经实现好的类。
Object类中equals()方法默认比较的是地址。
接口和数组都是引用类型 都可以进行向上转型操作
因为object类可以接收任意的引用数据类型,所以在很多的类库设计上都用object作为方法的参数,例如Basedao中传参进行比较。
匿名内部类的作用是可利用内部类创建不具有名称的对象,并利用它访问里面的成员。eciplse----- Winterday-----noinner
获取方法名在任意一个方法内:
Thread.currentThread().getStackTrace()[1].getMethodName();
获取类名名在任意一个方法内(需要截取):
String k = com.getClass().getName();