目录
一、接口
一方面,有时必须要从几个类中派生出一个子类,继承它们所有的属性和方法。但是Java不支持多重继承,有了接口,就可以实现多重继承的效果。
接口的使用
1.接口使用interface来定义
2.Java中,接口和类是并列的两个结构
3.如何定义接口:定义接口中的成员
3.1 JDK7及以前:只能定义全局常量和抽象方法
>全局常量:public static final的,但是书写时,可以省略不写
>抽象方法:public abstract的
3.2JDK8 :除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法
4.接口中不能定义构造器!意味着接口不可以实例化。
5.Java开发中,接口通过让类去实现(immplements)的方式来使用
如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化
如果实现类没有覆盖接口中所有的抽象方法,则此实现类任为一个抽象类。
package zhuyuan;
public class InterfaceTest {
public static void main(String[] args){
System.out.println(Flyable.MAX_SPEED);
System.out.println(Flyable.MIN_SPEED);
Plane plane=new Plane();
plane.fly();
}
}
interface Flyable{
//全局常量
public static final int MAX_SPEED=7900;
int MIN_SPEED=1;//省略了 public static final
//抽象方法
public abstract void fly();
void stop();
}
class Plane implements Flyable{
@Override
public void fly() {
System.out.println("飞机起飞");
}
@Override
public void stop() {
System.out.println("飞机停下");
}
}
abstract class Kite implements Flyable{
@Override
public void fly() {
}
}
6.Java类可以实现多个接口--》弥补了Java单继承的局限性
格式:class AA extends BBimplements CC,DD,EE
package zhuyuan;
public class InterfaceTest {
public static void main(String[] args){
System.out.println(Flyable.MAX_SPEED);
System.out.println(Flyable.MIN_SPEED);
Plane plane=new Plane();
plane.fly();
}
}
interface Flyable{
//全局常量
public static final int MAX_SPEED=7900;
int MIN_SPEED=1;//省略了 public static final
//抽象方法
public abstract void fly();
void stop();
}
interface Attackable{
void attack();
}
class Bullet implements Flyable,Attackable{
@Override
public void fly() {
}
@Override
public void stop() {
}
@Override
public void attack() {
}
}
7.接口和接口之间可以继承,而且可以多继承,在下面的代码中CC就成功继承了AA,BB,所以我们的bullet在调用CC接口的时候,需要把AA和BB中定义的方法全部去实现。
class Bullet implements Flyable,Attackable,CC{
@Override
public void fly() {
}
@Override
public void stop() {
}
@Override
public void attack() {
}
@Override
public void method1() {
}
@Override
public void method2() {
}
}
interface AA{
void method1();
}
interface BB{
void method2();
}
interface CC extends AA,BB{
}
8.接口具体的使用,体现多态性
9.接口实际上是一种规范。
以下是我们模拟实现USB传输协议的简单形式,并且展示了四种与接口相关的匿名和非匿名写法。
package zhuyuan;
public class USBtest {
public static void main(String[] args) {
Computer com=new Computer();
//1.创建了接口的非匿名实现类的非匿名对象
Flash flash=new Flash();
com.transferData(flash);
//2.创建了接口的非匿名实现类的匿名对象
com.transferData(new Printer());
//3.创建了接口的匿名实现类的非匿名对象
USB phone=new USB() {
@Override
public void start() {
System.out.println("给手机传输数据和充电");
}
@Override
public void stop() {
System.out.println("停止给手机传输数据和充电");
}
};
com.transferData(phone);
//4.创建了接口的匿名实现类的匿名对象
com.transferData(new USB() {
@Override
public void start() {
System.out.println("mp3传输数据和充电");
}
@Override
public void stop() {
System.out.println("mp3传输数据和充电");
}
});
}
}
class Computer{
public void transferData(USB usb){
usb.start();
System.out.println("传输具体数据的细节");
usb.stop();
}
}
interface USB{
void start();
void stop();
}
class Flash implements USB{
@Override
public void start() {
System.out.println("U盘开启工作");
}
@Override
public void stop() {
System.out.println("U盘结束工作");
}
}
class Printer implements USB{
@Override
public void start() {
System.out.println("打印机开启工作");
}
@Override
public void stop() {
System.out.println("打印机结束工作");
}
}
二、代理模式(Proxy)
Object就是接口,Objectlmpl就是被代理类,Proxyobject就是代理类。
这就好比是我们出去租房子,但是我们工作太忙了,没有时间去找房子,于是我们通过一些方式找到了一些租房机构来帮助我们寻找合适的房子。
下面的代码是一个与联网相关的代理。
Network是我们联网的接口
Server想要联网就需要调用这个NetWok的忌口,然后重写NetWork中的全部方法
而我们的proxyServere调用了network接口,并且创建了一个私有的network属性的work,将我们除了联网之外的检查网络工作一同封装成了我们的新的联网操作。
最后我们在调用的时候,我们首先创建了一个真实的被代理类,然后创建一个代理,将我们被代理的对象传递给代理,紧接着就让代理帮助我们完成了网络连接的工作。
也就是说,在这种模式下,用户类只需要写他们核心想做的事情,其他的事情交给代理类去完成即可。
package zhuyuan;
//接口的应用:代理模式
public class NetWorkTest {
public static void main(String[] args) {
Server server=new Server();
ProxyServer proxyServer=new ProxyServer(server);
proxyServer.browse();
}
}
interface NetWork{
public void browse();
}
//被代理类
class Server implements NetWork{
@Override
public void browse() {
System.out.println("真实的服务器访问网络");
}
}
//代理类
class ProxyServer implements NetWork{
private NetWork work;
public ProxyServer(NetWork work){
this.work=work;
}
public void check(){
System.out.println("联网之前的检查工作");
}
@Override
public void browse() {
check();
work.browse();
}
}
三、工厂设计模式
工厂模式:实现了创建者与调用者的分离,即将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的
分类
简单工厂模式:用来生产统一登记结构中的任意产品(对于增加新的产品,需要修改已有的代码)
工厂方法模式:用来生产统一登记结构中的固定产品(支持增加任意产品)
抽象工厂模式:用来生产不同产品族的全部产品。(对于增加新的产品,无能为力:支持增加产品族)
1.无工厂模式
无工厂模式就是按照我们之前的写法,先用一个接口定义好规范,然后让多个不同的类去调用这个接口,然后满足这个规范,形成我们的不同的类。
package zhuyuan;
//创建一个汽车的接口,定义汽车运行的抽象方法。
interface Car{
void run();
}
//将我们的奥迪类调用我们的汽车接口,并且重写其中的运行类
class Audi implements Car{
public void run() {
System.out.println("奥迪在跑");
}
}
//将我们的比亚迪类调用我们的汽车接口,并且重写其中的运行类
class BYD implements Car{
public void run() {
System.out.println("比亚迪在跑");
}
}
//测试代码
//先分别创建一辆新的奥迪和比亚迪
//然后分别调用奥迪车的运行代码和比亚迪车的运行代码。
public class factory {
public static void main(String[] args) {
Car a = new Audi();
Car b = new BYD();
a.run();
b.run();
}
}
2.简单工厂模式
简单工厂模式的特点,就是首先将如何创建每一种车的方式写好,然后将我们不同的造车方式告诉我们的工厂,然后我们的工厂会随着我们调用的需要去建造不同的车。
package zhuyuan;
//这里的代码和我们的无工厂模式相同
interface Car {
void run();
}
class Audi implements Car {
public void run() {
System.out.println("奥迪在跑");
}
}
class BYD implements Car {
public void run() {
System.out.println("比亚迪在跑");
}
}
//这里我们开始定义工厂类,让工厂为我们造车
//工厂类
class CarFactory {
//方式一
public static Car getCar(String type) {
if ("奥迪".equals(type)) {
return new Audi();
} else if ("比亚迪".equals(type)) {
return new BYD();
} else {
return null;
}
}
}
//下面为我们的测试代码
//我们可以看到,我们想要什么种类的汽车,只要将我们对应的名字传递给我们工厂就可以了
public class factory {
public static void main(String[] args) {
Car a = CarFactory.getCar("奥迪");
a.run();
Car b = CarFactory.getCar("比亚迪");
b.run();
}
}
3.工厂方法模式
相比于上面的形式,我们的工厂方法模式生成了两个不同的工厂类去生产我们不同种类的车。
package zhuyuan;
interface Car{
void run();
}
//两个实现类
class Audi implements Car{
public void run() {
System.out.println("奥迪在跑");
}
}
class BYD implements Car{
public void run() {
System.out.println("比亚迪在跑");
}
}
//工厂接口
interface Factory{
Car getCar();
}
//两个工厂类
class AudiFactory implements Factory{
public Audi getCar(){
return new Audi();
}
}
class BydFactory implements Factory{
public BYD getCar(){
return new BYD();
}
}
public class factory {
public static void main(String[] args) {
Car a = new AudiFactory().getCar();
Car b = new BydFactory().getCar();
a.run();
b.run();
}
}
四、JAVA8新特性
JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法
静态方法:使用static关键字修饰。可以通过接口直接调用静态方法,并执行其他方法体。可以在标注库中找到像Collection/Collections或者Path/Paths这样成对的接口和类
默认方法:默认方法使用default关键字修饰。可以通过实现类对象来调用。JAVA在已有的接口中提供新的方法的同时,还保持了与旧版本代码的兼容性。
//知识点1:接口中的静态方法,只能通过接口来调用
CompareA.method1();
//知识点2:通过实现类的对象,可以调用接口中的默认方法
//如果实现类重写了接口中的默认方法,调用时,任然调用的是重写之后的方法。
s.method2();
//知识点3.如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的方法
//那么子类在没有重写此方法的情况下,默认调用的是父类中同名同参数的写法。--类优先原则
s.method3();
//知识点4:如果实现类实现了多个接口,而这多个接口欧中定义了同名同参数的默认方法,
//那么在实现类没有重写此方法的情况下报错。--》接口冲突。
//这就需要我们必须在实现类中重写此方法
package zhuyuan;
public interface CompareA {
//静态方法
public static void method1(){
System.out.println("CompareA:北京");
}
//默认方法
public default void method2(){
System.out.println("CompareA:上海");
}
//默认方法
default void method3(){
System.out.println("CompareA:上海");
}
}
package zhuyuan;
public interface CompareB {
default void method3(){
System.out.println("CompareB:上海");
}
}
package zhuyuan;
public class SuperClass {
public void method3(){
System.out.println("Superclass:上海");
}
}
package zhuyuan;
public class SubClassTest {
public static void main(String[] args) {
SubClass s = new SubClass();
//知识点1:接口中的静态方法,只能通过接口来调用
CompareA.method1();
//知识点2:通过实现类的对象,可以调用接口中的默认方法
//如果实现类重写了接口中的默认方法,调用时,任然调用的是重写之后的方法。
s.method2();
//知识点3.如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的方法
//那么子类在没有重写此方法的情况下,默认调用的是父类中同名同参数的写法。--类优先原则
s.method3();
//知识点4:如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,
//那么在实现类没有重写此方法的情况下报错。--》接口冲突。
//这就需要我们必须在实现类中重写此方法
}
}
class SubClass extends SuperClass implements CompareA,CompareB{
public void method2(){
System.out.println("Subclass:上海");
}
public void method3(){
System.out.println("Subclass:深圳");
}
//知识点5:如何在子类(或实现类)的方法中调用父类、接口中被重写的方法。
public void myMethod(){
method3();//调用自己定义的重写的方法
super.method3();//调用的是父类中的声明
//调用接口中的默认方法
CompareA.super.method3();
CompareB.super.method3();
}
}
五、内部类
当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个群内部的完整结构最好使用内部类。
在Java中,允许一个类的定义位于另一个类的内部。前者称为内部类,后者称为外部类
Inner class一般用在定义它的类或语句块之内,在外部引用它时必须给出完整的名称。
Inner class的名字不能与包含它的外部类类名相同;
分类:成员内部类(static成员内部类和非static成员内部类)
局部内部类、匿名内部类
1.内部类 1.java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类 2.内部类的分类:成员内部类(静态、非静态)vs局部内部类。(方法内、代码块内。构造器内) 3.成员内部类: 一方面:作为外部类的成员: >调用外部类的结构 >可以使用static修饰 >可以被四种不同的权限修饰。 另一方面:作为一个类: >类内可以定义属性、方法、构造器等 >可以被final修饰,表示此类不能被继承。不使用final,可以被继承。 >可以被abstract修饰。4.关注如下3个问题
4.1如何实例化成员的内部类对象
4.2如何在成员内部类中区分调用外部类的结构
4.3开发中局部内部类的使用。
以下为内部类的测试代码
package zhuyuan;
public class InnerClassTest {
public static void main(String[] args) {
//创建Dog实例(静态的成员内部类)
Person.Dog dog=new Person.Dog();
dog.show();
//创建bird实例(非静态的内部类成员)
// Person.Bird bird=new Person.Bird();//错误的
//因为我们在这里bird是非静态的实例化变量,所以我们需要
//先创建一个人的实例,我们的bird才会被加载
Person p=new Person();
Person.Bird bird=p.new Bird();
bird.sing();
System.out.println();
bird.display("可达鸭");
}
}
class Person{
String name="李华";
int age;
public void eat(){
System.out.println("人:吃饭饭");
}
//静态成员内部类
static class Dog{
String name;
int age;
public void show(){
System.out.println("二狗");
}
}
//非静态成员内部类
class Bird{
String name="愤怒的小鸟";
public Bird(){
}
public void sing(){
System.out.println("我是一只小小鸟");
Person.this.eat();//调用外部类的属性(非静态)
}
public void display(String name){
System.out.println(name);//方法的形参
System.out.println(this.name);//内部类的属性
System.out.println(Person.this.name);//外部类的属性
}
}
public void method(){
//局部内部类
class AA{
}
}
{
//局部内部类
class BB{
}
}
public Person(){
//局部内部类
class CC{
}
}
}
实际生活中的应用
package zhuyuan;
public class InnerClassTest1 {
public void method(){
//局部内部类
class AA{
}
}
//返回一个实现了comparable接口的类的对象
public Comparable getComparable(){
//创建一个实现了Comparable接口的类:局部内部类
//方式一:
//非匿名实现类的匿名对象
class Mycomparable implements Comparable{
@Override
public int compareTo(Object o) {
return 0;
}
}
return new Mycomparable();
//方式二:
//匿名实现类的匿名对象(实现类没有名字,对象也没有名字)
return new Comparable() {
@Override
public int compareTo(Object o) {
return 0;
}
}
}
}
在局部内部类的方法中(比如:show)如果调用局部内部类所声明的方法(比如:method)中的局部变量的话,要求此局部变量声明为final的。
jdk7及之前的版本:要求此局部变量显式的声明为final的
jdk8之后的版本:可以省略final的声明