这个更注重于是不是
例如小狗是动物,那么小狗就继承父抽象类动物,再比如:黑白打印机是打印机,那么黑白打印机就继承抽象类打印机。
一个类中如果存在抽象方法,那么他必须是抽象类
抽象类VS普通类
抽象类不能被直接实例化,但是可以创建一个引用变量,其类型是一个抽象类,指向非抽象的子类实例
普通类可以被实例化
抽象类中可以存在抽象方法,普通类中不能有抽象方法
世界上并不存在一个单纯是动物的东西,动物是一个抽象的集合,你只能说狗是动物,猫是动物,但是你没法真的实例化一个“动物”,所以动物就是抽象类。打印机也是如此,黑白打印机是打印机,你可以实例化一个黑白打印机,但一般不会去实例化“打印机”。
“你是人,我是人,但没有’人是人’“
//抽象方法打印
public abstract class Printer{
public abstract void print();
}
//重写打印方法的彩色打印机类
public class CPrinter extends Printer{
@Override
public void print(){
System.out.println("这是一个彩色打印机,打印了彩色的文件");
}
}
//重写打印方法的黑白打印机类
public class BWPrinter extends Printer{
@Override
public void print(){
System.out.println("这是一个黑白打印机,他打印了一张黑白图片");
}
}
//测试类
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
while (true){
System.out.println("请问你要选择什么打印机? 1、黑白打印机 2、彩色打印机");
int flag = input.nextInt();
Printer printer;
if (1==flag){
printer = new BWPrinter();
}else {
printer = new CPrinter();
}
printer.print();
System.out.println("=========================================");
}
}
抽象类中可以没有抽象方法,但包含了抽象方法的类必须被定义为抽象类
如果子类没有实现父类的所有抽象方法,子类必须被定义为抽象类
没有抽象构造方法,也没有抽象静态方法
抽象类中可以有非抽象的构造方法,创建子类的实例时可能调用
2、接口注重于能不能(功能)?
当一个类中所有的方法都是抽象方法时,这个类就可以定义为接口
接口是一种"引用数据类型",编译之后也是class文件
接口是完全抽象,接口不能被实例化,(不过让子类重写抽象方法后就可以使用)
接口定义:
public interface Xxx{
}
接口中只支持共有的静态常量+共有抽象方法(共有的即public)
接口中所有的元素都是public关键字修饰的
接口中变量默认被public static final修饰,(相当于常量,变量名要全大写)
接口中的抽象方法的public abstract可以省略(抽象方法没有方法体,即 public abstract void 方法名();)
接口支持多继承,并且接口只可以继承接口
public interface Xxx extends A,B{
}
接口和类之间是实现关系,通过implements关键字表示
public class 类名 implements 接口名{}
此时上面这个就是接口的子类,或者说实现类,它只有两个选择,要么重写接口中的所有抽象方法,要么被定义为抽象类,这个子类也可以继承多个接口,但是必须把所有抽象方法全部重写
接口的两个意义:
规则的定义
程序的扩展性
接口没有构造方法,但是子类中可以使用super(),因为所有的类都直接或者间接的继承了Object
接口的成员变量:只能是常量,系统会默认加上public static final
接口的成员方法:只能是抽象方法,系统会默认加上public abstract
2、1JDk8以后的新特性允许在接口中定义非抽象方法(即带有方法体),但是需要使用default修饰,即默认方法,用来解决接口升级的问题
默认方法的定义格式:
public default 返回值类型 方法名(参数列表){}
默认方法不是抽象方法,实现时,不强制要求重写,但是重写时必须去掉default关键字
实现多个接口时,若存在同名默认方法,就必须重写。
允许在接口中定义static静态方法
静态方法定义格式:
public static 返回值类型 方法名(参数列表){}
静态方法只能通过接口名调用,不能通过实现类类名或者对象名调用,也因此实现多个接口,且里面有重名静态方法时,不会报错
public可以省略,static不可以
JDK9中可以存在私有方法
2、2类和接口的关系类和类:
继承关系,只能单继承,但可以多级继承
类和接口:
实现关系,可以单实现,也可以多实现,也可以继承一个类的同时实现多个接口
接口和接口:
继承关系,可以单继承,也可以多继承
3、面向对象的设计原则多用组合,少用继承
针对接口编程
针对扩展开放,针对改变关闭
4、内部类在一个类中定义一个类,例如A类中定义B类,那么B类就是内部类
public class Demo{
public static void main(String[] args){
Outer.Inner i = new Outer().new Inner();
System.out.println(i.num);
i.show();
}
}
class Outer{
Private int a = 10;
class Inner{
int num = 10;
public void show(){
System.out.println("Inner...show");
//内部类可以直接访问外部类成员,包括私有
System.out.println(a);
}
}
}
外部类要想访问内部类成员,就必须创建对象
按照内部类在类中定义的位置不同,可以分为以下两种形式:
在类的成员位置:成员内部类
在类的局部位置:局部内部类
4、1成员内部类成员内部类也是成员,也就可以被一些修饰符修饰例如(private static)
private:
私有成员内部类访问:在自己所在的外部类中创建对象访问
public class Demo{
public static void main(String[] args){
Outer o = new Outer();
o.method();
}
}
class Outer{
private class Inner{
public void show(){
System.out.println("Inner...show");
}
public void method(){
Inner i = new Inner();
i.show
}
}
}
static:
静态成员内部类访问格式:
外部类名.内部类名 对象名 = new 外部类名.内部类名();
public class Demo{
public static void main(String[] args){
//外部类名.内部类名 对象名 = new 外部类名.内部类名();
Outer.Inner oi = new Outer.Inner();
oi.show();
//被static修饰的成员,属于它的类,所以可以一路类名.下去
Outer.Inner.method();
}
}
class Outer{
static class Inner{
public void show(){
System.out.println("Inner...show");
}
public static void method(){
System.out.println("Inner...method");
}
}
}
4、2局部内部类
局部内部类是在方法中定义的类,外界是无法直接使用的,需要在方法内部创建对象并使用,该类可以直接访问外部类的成员,也可以访问方法内的局部变量
public class Demo{
public static void main(String[] args){
Outer o = new Outer();
o.method
}
}
class Outer{
int a =10;
public static void method(){
int b =20;
class Inner{
public void show(){
System.out.println("show....");
System.out.println(a);
System.out.println(b);
}
}
Inner i = new Inner();
i.show();
}
}
4、3匿名内部类
本质上是一个特殊的局部内部类(定义在方法内部)
匿名内部类就是将继承/实现,方法重写,创建对象放在一步进行
前提条件:需要存在一个接口或者类
格式:
new 类名或者接口名(){
重写方法;
};
在此之前如果要使用一个接口的方法
1、创建实现类,通过implements关键字去实现接口
2、重写方法
3、创建实现类对象
4、调用重写后的方法
public class Test {
public static void main(String[] args) {
InterImpl ii = new InterImpl();
ii.show();
}
}
interface Inter{
void show();
}
class InterImpl implements Inter{
@Override
public void show(){
System.out.println("InterImpl 重写的show方法")
}
}
用了匿名内部类之后简化为:
public class Test {
public static void main(String[] args) {
new Inter(){
@Override
public void show(){
System.out.println("匿名内部类中的show方法")
}
}.show();
}
interface Inter{
void show();
}
匿名内部类就是将继承/实现,方法重写,创建对象放在一步进行
如果一个接口中有多个方法
public class Test {
public static void main(String[] args) {
//父类引用指向子类对象——多态
Inter i = new Inter(){
@Override
public void show1(){
System.out.println("匿名内部类中的show1方法")
}
@Override
public void show2(){
System.out.println("匿名内部类中的show2方法")
}
};
i.show1();
i.show2();
}
interface Inter{
void show1();
void show2();
}
匿名内部类的使用场景:当方法的形式参数为接口或者抽象类时,可以将匿名内部类作为实际参数进行传递
5、箭头函数Lambda表达式 public interface HardDisk {
String getCapacity();
}
public class Test {
public static void main(String[] args) {
//Lambda表达式 箭头函数
//首先如果我们的一个类为只有一个方法的类
//那么我们使用匿名内部类时
//可以使用以下方法实现,将参数写在第一个位置,之后跟上一个箭头,接着是大括号,写代码
HardDisk hardDisk = () -> {
return "400GB";
};
}
}



