一、抽象类
1、为什么使用抽象类
类用于描述现实生活中的一类事物,类中有属性有方法,方法都有方法体。
某种情况下,父类只能知道子类应该具备一个怎样的方法,但是不能明确知道子类如何实现该方法
例如:几何图形(多态练习),所有几何图形都应该具备计算面积的功能,但是不同几何图形计算面积的方式不同
Java 为上述问题提供了相应的解决办法
Java 允许父类中只是提供一个方法的声明,不提供具体的实现,具体的实现交给子类来完成
该方法称为“抽象方法”,拥有一个或多个抽象方法的类,称为“抽象类”
2、如何使用抽象:abstract
1)使用 abstract 修饰的类称为“抽象类”
①格式:访问控制修饰符 abstract class 类名{}
②拥有一个或多个抽象方法的类必须是抽象类
③抽象类中可以有非抽象方法,抽象类中可以没有抽象方法
④**抽象类不能创建实例
⑤抽象类中可以声明构造器。
目的:当子类继承父类后,继承父类中所有的属性和方法,因此子类需要知道父类如何进行初始化
- 使用 abstract 修饰的方法称为“抽象方法”
①格式:访问控制修饰符 abstract 返回值类型 方法名(参数列表);
②子类继承父类后,若重写了父类中“所有”的抽象方法,该类是具体类,可以创建实例
③子类继承父类后,若没有重写父类中“所以”的抽象方法,该类必须是抽象类,不可以创建实例
abstract class Person{
private String name;
private int age;
public Person(){}
public void setName(String name){
this.name = name;
}
//人都应该具备一个说话的功能,但是不同的人说话的方式不同
public abstract void speak();
}
class Chinese extends Person{
public void speak(){
System.out.println("中国人说汉语");
}
}
abstract class American extends Person{
//public abstract void speak();
}
3、abstract 关键字的注意
① abstract 和 final 不能同时使用
② abstract 和 static 不能同时使用
③ abstract 和 private 不能同时使用
④ abstract不能用来修饰:属性、构造器等结构,不能用来修饰私方法、静态方法。
二、接口
可以定义多个不相关事物的相同功能
1、如何使用接口(如下以jdk1.7为标准)
①接口与类时平级的
关键字:interface
如:
public interface Flyer{}
②可以把接口理解为特殊的抽象类,因为jdk1.7前接口中只能定义“全局静态常量”和抽象方法
//全局静态常量
int NUM = 100;//public static final
//抽象方法
void fly();//public abstract
③接口中不能有变量、构造器、代码块
④**接口不能创建实例
⑤接口就是用来被实现的
实现接口关键字:implements
如:
class Bird implements Flyer{}
⑥实现接口的类称为“实现类”,实现类的功能和“继承”一样的,可以继承接口中所有的成员
⑦若实现类实现了接口中所有的抽象方法,该类为具体类,可以创建实例
若实现类没有实现接口中所有的抽象方法,该类必须是抽象类,不能创建实例
⑧接口可以多实现 — 解决了 Java 中单继承的局限性
如:
class Bird implements Flyer, Runner{}
⑨接口不能继承任何类,接口可以继承接口并且可以多继承接口
⑩一个类可以继承另一个类,同时实现多个接口
如:
class Bird extends Animal implements Flyer, Runner{}
注意:先继承,后实现
体会:
- 1.接口使用上也满足多态性
- 2.接口,实际上就是定义了一种规范
- 3.开发中,体会面向接口编程!
体会面向接口编程的思想
面向接口编程:我们在应用程序中,调用的结构都是JDBC中定义的接口,不会出现具体某一个。
2、jdk1.8对于接口的升级
(Lambda表达式需要函数式接口(接口中只有一个抽象方法的接口)的支持)
//知识点1:接口中定义的静态方法,只能通过接口来调用。
//知识点2:通过实现类的对象,可以调用接口中的默认方法。
//如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法
//知识点3:如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的默认方法,那么子类在没重写此方法的情况下,默认调用的是父类中的同名同参数的方法。–>类优先原则
//知识点4:如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,
//那么在实现类没重写此方法的情况下,报错。–>接口冲突。
//这就需要我们必须在实现类中重写此方法
//知识点5:如何在子类(或实现类)的方法中调用父类、接口中被重写的方法
public void myMethod(){
method3();//调用自己定义的重写的方法
super.method3();//调用的是父类中声明的
//调用接口中的默认方法
CompareA.super.method3();
CompareB.super.method3();
}
public class DefaultMethodTest {
public static void main(String[] args) {
SubClass sc = new SubClass();
//若接口中与父类中具有相同方法签名的方法时,默认为类优先原则,接口中的默认方法会被忽略
sc.show();
MyInterface.test();
}
}
interface MyInterface{
default void show(){
System.out.println("接口中的默认方法");
}
public static void test(){
System.out.println("接口中的静态方法");
}
}
interface MyFun{
default void show(){
System.out.println("MyFun 接口中的默认方法");
}
}
class MySuperClass{
public void show(){
System.out.println("父类中的方法");
}
}
class SubClass /*extends MySuperClass*/ implements MyInterface, MyFun{
@Override
public void show() {
MyFun.super.show();
}
}
面试题:
抽象类和接口的异同?
相同点:不能实例化;都可以包含抽象方法的。
不同点:
1)把抽象类和接口(java7,java8,java9)的定义、内部结构解释说明
2)类:单继承性 接口:多继承
类与接口:多实现
三、内部类
1、成员内部类
在类中声明另一个类,里面的类称为内部类,外面的类称为外部类
成员内部类的理解:
一方面,作为外部类的成员:
-
>调用外部类的结构
-
>可以被static修饰
-
>可以被4种不同的权限修饰
另一方面,作为一个类:
-
> 类内可以定义属性、方法、构造器等
-
> 可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承
-
> 可以被abstract修饰
class Person{
private String name;
public Person(){
System.out.println(name);
setName("李四");
Computer com = new Computer();
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
//成员内部类
public class Computer{
private String name;
public Computer(){}
public void setName(String name){
System.out.println("局部变量 name:" + name);
System.out.println("当前内部类Computer对象的 name: " + this.name);
System.out.println("当前外部类Person对象的 name:" + Person.this.name);
System.out.println("不需要区分使用同级别成员:" + getName());
this.name = name;
}
}
//对类的隐藏
private class Head{
}
//静态内部类
static class Mobile{
public void show(){
System.out.println("静态内部类中的方法");
}
}
}
class InnerClassTest{
public static void main(String[] args){
//创建静态内部类对象
Person.Mobile pm = new Person.Mobile();
pm.show();
//创建非静态内部类的对象
Person p = new Person();
Person.Computer pc = p.new Computer();
pc.setName("IBM");
}
}
2、局部内部类
//如下方式使用较少
public void show(){
int num = 10;
//局部内部类
class Inner{
public void test(){
System.out.println(num);
//注意:若局部内部类中使用了同级别的局部变量,该局部变量必须使用 final 修饰
//jdk1.7 必须手动加 final,jdk1.8默认为 final
}
}
Inner in = new Inner();
}
//
public Comparator getComparator(){
//
return new MyComparator();
}
public Comparator getComparator1(){
//若该类仅对于当前方法有用,可以声明为局部内部类
class MyComparator implements Comparator{
@Override
public int compare(Object o1, Object o2) {
return 0;
}
}
return new MyComparator();
}
public Comparator getComparator2(){
//匿名内部类
Comparator com = new Comparator(){
@Override
public int compare(Object o1, Object o2) {
return 0;
}
};
return com;
}
public Comparator getComparator3(){
//
return new Comparator(){
@Override
public int compare(Object o1, Object o2) {
return 0;
}
};
}
总结:
成员内部类和局部内部类,在编译以后,都会生成字节码文件。
格式:成员内部类:外部类
内
部
类
名
.
c
l
a
s
s
局
部
内
部
类
:
外
部
类
内部类名.class 局部内部类:外部类
内部类名.class局部内部类:外部类数字 内部类名.class
四、枚举类
是 jdk1.5 后出的特性,可以定义有限数量的可穷举数据集。
- 1.枚举类的理解:类的对象只有有限个,确定的。我们称此类为枚举类
- 2.当需要定义一组常量时,强烈建议使用枚举类
- 3.如果枚举类中只一个对象,则可以作为单例模式的实现方式。
1、自定义枚举
①私有化构造器
②类的内部创建对象
package com.atguigu.java;
/*
自定义枚举类
*/
public class Season1 {
private String seasonName;
private String seasonDesc;
//2. 类的内部创建对象
public static final Season1 SPRING = new Season1("春天", "春眠不觉晓");
public static final Season1 SUMMER = new Season1("夏天", "夏天蚊子咬");
public static final Season1 AUTUMN = new Season1("秋天", "秋天叶子黄");
public static final Season1 WINTER = new Season1("冬天", "冬天雪花飘");
//1. 私有化构造器
private Season1(String seasonName, String seasonDesc){
this.seasonName = seasonName;
this.seasonDesc = seasonDesc;
}
public String getSeasonName() {
return seasonName;
}
public void setSeasonName(String seasonName) {
this.seasonName = seasonName;
}
public String getSeasonDesc() {
return seasonDesc;
}
public void setSeasonDesc(String seasonDesc) {
this.seasonDesc = seasonDesc;
}
@Override
public String toString() {
return "Season{" +
"seasonName='" + seasonName + '\'' +
", seasonDesc='" + seasonDesc + '\'' +
'}';
}
}
2、使用 enum 关键字
valueOf(String name) : 根据枚举类对象的名称,获取枚举类对象
values() : 获取当前枚举类中所有的枚举类对象,组成的数组
public enum Season1 {
SPRING,
SUMMER,
AUTUMN,
WINTER;
}
3、枚举类实现接口
public enum Season1 implements MyInterface{
SPRING{
public void show(){
System.out.println("春天");
}
},
SUMMER{
public void show(){
System.out.println("夏天");
}
},
AUTUMN{
public void show(){
System.out.println("秋天");
}
},
WINTER{
public void show(){
System.out.println("冬天");
}
};
/*public void show(){
System.out.println("季节");
}*/
}