Java interface 和 implements关键字【接口,看这篇就够了】_interface implements

public interface Sport extends Law,People{
void run();
void competition();
}


* 好,具体测试不给出了,主要是看这个接口可以继承多个接口,可以看出Sport接口使用了extends关键字继承类Law和People这两个接口



> 
> 以上的这两个特点很重要,也是弥补了Java类不能多继承的缺陷
> 
> 
> 


5. 一个类,它可以在继承父类的情况下同时实现接口



class Dog extends Animal implements Runnging,Drinking{
}


### 📕接口的作用和意义


有些刚刚接触Java接口的小伙伴就很疑惑,这个接口到底是用来干嘛的呢,它究竟有什么具体的作用



> 
> 首先我们来总的概括一下,其实就是一句话:【**定义一个公共规范,实现一个统一访问**】
> 
> 
> 


* 对于公共规范这个概念,就是大家都认可的,是一种标准,就像是**USB**(通用串行总线)一样,这个接口是很多家公司联合提出的,因此属于一个规范,在日常生活中,我们使用的很多设备都拥有**USB接口**,这个USB接口呢,其实就很像Java中所说的接口;
* 如果有一个物件,比如说**笔记本,拥有这个接口**,也相当于是实现了这个接口,那就说明笔记本这个类有了USB这个功能,外部设备便可以与它产生一个联系,比如说最常见的U盘,只要是有USB接口的地方,那么这个U盘都可以使用,这么说大家应该有点清楚了吧,下面会更加详细地深入了解接口
* 对于统一访问,举个例子,对于LOL这款游戏大家应该都玩过,一个英雄,是不是一定会有**相同的功能**,比如说`攻击、点塔、补刀`这些,但是LOL中157个英雄,假设它们都对应一个类,难道在每个英雄类中都去写这三个功能吗,那一定不会,这是就可以定义一个**基本英雄功能接口**,里面封装了所有英雄所具备的基本能力,然后所有英雄类都去访问这个接口就可以  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/eb039cc498f14e898e98dfd633011c0d.jpeg#pic_center)


## 🌳接口的UML图(类图)



> 
> 初步入门了接口后,接下去我们就要了解接口与它的实现类之间所存在的**逻辑框架关系**,也就是类图,这可以进一步帮助我们去理解接口
> 
> 
> 


### 🍃UML图的基本概念



> 
> 统一建模语言(Unified Modeling Language,**UML**)是用来设计软件的可视化建模语言。可以帮助我们简单、统一、图形化、能表达软件设计中的动态与静态信息
> 
> 
> 


### 🍃UML图的作用


* 可以帮助我们清晰勾勒出一个类族的框架接口,继而对此项目整体逻辑接口更加了解
* UML图是系统分析和设计阶段的重要产物,是系统编码和测试的重要模型


### 🍃接口UML图的基本结构和组成


* 对于接口的UML图与类的UML图很类似,主要是使用一个长方形去描述一个类或接口,将这个长方形垂直地分为3层
* 第一层是**名字层**,接口的字形必须是斜体字形,而且需要用<>修饰名字,格式为【接口修饰符\n接口名称】
* 第二层是**常量层**,列出接口中的常量及类型,格式为【常量名字:类型】
* 第三层是**方法层**,也称操作层,列出接口中的方法及返回类型,格式为【方法名字(参数列表):类型】


### 🎈继承关系类图与接口图的区别


* 子类与父类的继承关系所呈现的UML类图


![在这里插入图片描述](https://img-blog.csdnimg.cn/7753b8e8ebd94a46943673898f661b59.jpeg#pic_center)


* 接口与实现类所呈现的UML类图


![在这里插入图片描述](https://img-blog.csdnimg.cn/50c5cb24288e41b0939ac3fb05a2e256.jpeg#pic_center)


* 相信通过这两张UML图的对比分析,你对UML类图也有了一个基本的见解了


## 🌳接口回调与多态的联系



> 
> 在前面将多态的时候,讲到上转型对象时我有提到过接口回调这个东西,这在接口中是比较重要的,因此做一个区分
> 
> 
> 


### 📚权威解释


* 对于向上转型,就是父类引用去引用子类对象
* 而对于接口回调,就是把实现某一接口的**类创建的对象的引用**赋值给该接口【声明的接口变量】,那么该接口就可以调用被类实现的接口方法以及接口提供的default方法
* 对于它们二者的区别,还要说到使用接口的核心原因:为了能够向上转型为多个基类型。即利用接口的多实现,可向上转型为多个接口基类型,从实现了某接口的对象,得到对此接口的引用,与向上转型为这个对象的基类,实质上效果是一样的
* 所以对于接口回调,强调使用接口来实现回调对象方法使用权的功能;对于向上转型,则牵涉到多态和运行期绑定的范畴  
 以上解释来自《Tinking in Java》这本书


### 🍃具体案例分析



> 
> 说了这么多概念,您对接口回调一定还没有一个很清晰的认识,接下去我们通过一个小案例一起来看看
> 
> 
> 



public interface ShowMessage {
void show(String s);
}



public class TV implements ShowMessage {
@Override
public void show(String s) {
System.out.println(“tvtvtvtvtv”);
System.out.println(s);
System.out.println(“tvtvtvtvtv”);
}
}



public class PC implements ShowMessage {
@Override
public void show(String s) {
System.out.println(“pcpcpcpcpc”);
System.out.println(s);
System.out.println(“pcpcpcpcpc”);
}
}



public class test {
public static void main(String[] args) {
ShowMessage sm;
sm = new TV();
sm.show(“TCL电视机打开了”);

    System.out.println("-----------");

    sm = new PC();
    sm.show("Lenovo台式机打开了");
}

}


![在这里插入图片描述](https://img-blog.csdnimg.cn/1b61edff64b64474914832b5e3305b2a.jpeg#pic_center)


* 从这个小案例可以看出,对于接口回调,就是将一个实现接口的类所定义的对象的引用给到一个接口所声明的变量,然后上面说了,可以实现回调对象方法使用权的功能,也就是去调用子类重写接口中抽象方法


## 🌳函数接口与Lambda表达式



> 
> 讲完了接口回调,我们再来说一下函数接口与Lambda表达式
> 
> 
> 


### 🍃Lambda表达式


* 这个Lambda表达式的话也是JDK8新出的,当时出个这个概念的时候备受争议,因为这简直颠覆了大家的想象,都说居然可以这么去优化一个表达式,对此表示非常地惊奇🎃
* 接着就让我们先来了解一下这个Lambda表达式,了解一下它有什么优缺点



> 
> Lambda表达式,也可称为闭包。类似于JavaScript中的闭包,它是推动Java8发布的最重要的新特性
> 
> 
> 


* 优点


1、代码更加简洁


2、减少匿名内部类的创建,节省资源⭐


3、使用时不用去记忆所使用的接口和抽象函数


* 缺点


1、若不用并行计算,很多时候计算速度没有比传统的 for 循环快。(并行计算有时需要预热才显示出效率优势)


2、不容易调试。


3、若其他程序员没有学过 lambda 表达式,代码不容易让其他语言的程序员看懂⭐


* 上面提到了一个叫做**匿名内部类**,这个我还没讲到,放在下一篇文章,大家可以先去了解一下,[匿名内部类]( ),这是内部类的一种


### 🍃函数式接口



> 
> 然后我们再来了解一下函数式接口
> 
> 
> 


* 首先必须是接口、其次接口中有且仅有一个抽象方法的形式⭐
* 通常我们会在接口上加上一个@FunctionalInterface注解,标记该接口必须是满足函数式接口⭐


定义方法如下



@FunctionalInterface //一旦加上这个注解必须是函数式接口,里面只能有一个抽象方法
interface Swimming{
void swim();
//void run();
}


* 首先根据上面这个接口,我们去实现一个匿名内部类



public class LambdaDemo1 {
//Lambda表达式只能简化函数式接口的匿名内部类的写法形式
//Lambda表达式只能简化接口中只有一个抽象方法的匿名内部类形式
public static void main(String[] args) {
//实现了Swimming这个接口
Swimming s1 = new Swimming() {
@Override
public void swim() {
System.out.println(“老师游泳贼溜”);
}
};
go(s1);
go(new Swimming() {
@Override
public void swim() {
System.out.println(“学生游泳很开心”);
}
});
}

public static void go(Swimming s){
    System.out.println("开始。。。");
    s.swim();
    System.out.println("结束。。。");
}

}



> 
> 对于如何去进行一个简化,我们需要先了解其规则
> 
> 
> 


### 🍃简化规则定义


* **参数类型**可以省略不写
* 如果只有一个参数,参数类型可以省略,同时()也可以省略
* 如果Lambda表达式的方法体代码只有一行代码。可以省略大括号不写,同时要省略分号!
* 如果Lambda表达式的方法体代码只有一行代码。可以省略大括号不写。此时,如果这行代码是**return语句**,必须省略return不写,同时也**省略“;”不写**



> 
> 然后我们就对上面的代码进行一个简化
> 
> 
> 



Swimming s1 = new Swimming() {
// Swimming s1 = () ->{ //简化版
// System.out.println(“老师游泳贼溜”);
// };

Swimming s1 = () -> System.out.println("老师游泳贼溜");		//最终版
go(s1);


> 
> 到这里大家可能还是没有看懂,那我们再来多看几个,就能懂了
> 
> 
> 



public class LambdaDemo2 {
public static void main(String[] args) {
Integer[] ages = {66,99,33,78,12};

    //Arrays.sort(ages); 默认升序

    Arrays.sort(ages, new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o2 - o1;     //降序
        }
    });

// Arrays.sort(ages, (Integer o1, Integer o2) ->{
// return o2 - o1; //降序
// }
// );

// Arrays.sort(ages, (o1, o2) ->{
// return o2 - o1; //降序
// }
// );

    Arrays.sort(ages, (o1, o2) -> o2 - o1);
    System.out.println("排序后的内容为:" + Arrays.toString(ages));
}

}


* 好,我们来详细地说明一下,对于Arrays这个API的数组排序,相信大家用的是最多的,默认是升序,这里是进行了一个重写然后令其可以实现降序输出
* 首先,应该去掉的就是,因为我们只需要这个匿名内部类的形参列表和方法体代码,然后要加上一个【—>】箭头,要注意,这个箭头可不是C/C++里面的指针  
 new Comparator() {  
 @Override  
 public int **这段代码**
* 然后根据第一条规则可以知道, 参数类型可以省略不写,所以只留下(o1, o2)
* 接着就是省略这个reutrn和语句后面的分号“;”
* 最终的简化结果就是**Arrays.sort(ages, (o1, o2) -> o2 - o1);**


再来一个有关按钮监听事件ActionListener的匿名内部类形式简化



//Lambda表达式简化按钮监听器ActionListener的匿名内部类形式
public class LambdaDemo3 {
public static void main(String[] args) {
JButton btn = new JButton(“登录”);
//给登录按钮绑定点击时间监听器
// btn.addActionListener(new ActionListener() {
// @Override
// public void actionPerformed(ActionEvent e) {
// System.out.println(“登录一下~~~”);
// }
// });
//
// btn.addActionListener((ActionEvent e) ->{
// System.out.println(“登录一下~~~”);
// }
// );
//
// btn.addActionListener((e) ->{
// System.out.println(“登录一下~~~”);
// }
// );

    btn.addActionListener( e -> System.out.println("登录一下~~~"));
}

}


* 首先是一样,省略这一段代码  
 new ActionListener() {  
 @Override  
 public void actionPerformed
* 接着是省略形参值ActionEvent
* 最根据第二条规则,如果只有一个参数,参数类型可以省略,同时()也可以省略,省略e外的小括号
* 最终形式便是**btn.addActionListener( e -> System.out.println(“登录一下~~~”));**



> 
> 好,又看了两个小案例,这些您对Lambda表达式简化匿名内部类有了一个基本的认识了,接下来我们说一些小贴士
> 
> 
> 


### 💡细心小贴士


* 如果大家细心的话,对于有些方法,按住ctrl键鼠标点进去,就可以看到这是一个函数式接口,如果看到了【@FunctionalInterface】注解,那就表明这个匿名内部类可以使用Lambda表达式来简化,点进我们刚才那个sort()排序的Comparator接口,就可以看到这个注解



> 
> ![在这里插入图片描述](https://img-blog.csdnimg.cn/2940b8e8dbff4f95a287748be3321590.jpeg#pic_center)
> 
> 
> 



> 
> ![在这里插入图片描述](https://img-blog.csdnimg.cn/724b16a38f484772b0458b523b50faff.jpeg#pic_center)
> 
> 
> 


## 🌳深入理解接口【面向接口的思维】



> 
> 了解接口后,我们要开始第二层次,也就是理解接口,首先就是要进行思考,提出相应的问题
> 
> 
> 


### ❓提问一:为什么不在一个类中直接实现相应的方法,而是要先进行接口抽象呢?


* 答:这样会造成代码冗余,**众多类中都有相同的一个功能**,只是调用的对象不同,继而产生内存浪费。这时就可以使用接口去封装这个功能,通过父类引用去接收子类对象,从而实现多态


### ❓提问二:接口的真正用处在哪里,用接口可以帮助我们实现什么?


* 答:对于一个接口,上面在讲概念的时候有提到一些,就类似于一个**功能库**一般,在这个功能库中呢,你可以定义许多别人可能会用的到的功能,这样当别人有需要时,便无需去继承一个抽象类导致类族群混乱,或者自己重写定义一个方法导致增加内存。完全可以把大家都会用得到的功能,并且可以实现多态的功能放入此方法库,在定义这个方法的时候完全无需去考虑它是如何实现的,只需要定义好其标准以及参数的设定
* 因此可以看出,在一个项目开发时,拥有一些实用的接口是多么重要,既能有一个统一的规范、有一个严格的标准,而且还可以**提高开发的效率,减少类族的复杂性**,上面也讲到过,接口其实很好地弥补了Java无法多继承这个缺陷,当你继承了一个父类,但是又不想再添加一个祖先父类的抽象类,将类族混乱。**接口就是一个很好的选择,可以帮助我们实现想要实现的功能**


### ❓提问三:接口与抽象类如此地相似,为什么有的时候要使用接口而不用抽象类呢?


* 答:对于抽象类,它可以让自己的引用去接收子类对象;对于接口,它可以让自己声明的变量,一样去接收子类对象,它们都可以在获取到子类对象后调用子类重写的抽象方法,继而实现多态。
* 但是对于抽象类,它始终都是一个类,是需要被继承才能让子类去重写自己所拥有的抽象方法,但是**当一些子类继承了一些父类拥有但是自己却不需要的功能时**,这时候就会出问题,造成内存浪费。如果当我们仅仅是**为了实现多态,而且又是很多类都需要这个功能,却不想要去继承一个父类获取这个方法**,就可以将此方法写入接口,通过【implements】这个关键字去实现这个接口,继而在类内重写这个抽象方法来实现多态


## 🌳接口的实战项目演练



> 
> 在本小节中,我会设置三个实战项目,从浅入深,层层递进,帮助大家来更好地理解接口在实际的应用中到底是如何去使用的
> 
> 
> 


### “Hello World”【⭐】



> 
> 看到这个标题,你不会真的以为只是输出【Helllo World】吧,那是不会的,只是这个案例作为第一个,比较简易一些,帮助大家来回顾上面所学的知识点
> 
> 
> 


上代码



public interface SpeakHello {
public void speak();
}



public class CPeople implements SpeakHello{
@Override
public void speak() {
System.out.println(“你好”);
}
}



public class EPeople implements SpeakHello{
@Override
public void speak() {
System.out.println(“Hello”);
}
}



public class Hello {
public void lookHello(SpeakHello speakHello){
speakHello.speak(); //实现接口回调
}
}



public class test {
public static void main(String[] args) {
Hello hello = new Hello();

    hello.lookHello(new CPeople());
    hello.lookHello(new EPeople());

    hello.lookHello(new SpeakHello() {
        @Override       //匿名内部类
        public void speak() {
            System.out.println("Hello World");
        }
    });

    //简化版
    hello.lookHello(() -> System.out.println("H W"));	//Lambda表达式
}

}



> 
> ![在这里插入图片描述](https://img-blog.csdnimg.cn/aace3b41766742948ad419daf247abb7.jpeg#pic_center)
> 
> 
> 


* 第一个实战项目,作为我们对于上述所讲的接口的基本定义和实现以及接口回调、Lambda表达式做一个总结
* 首先,说话是一个能力,将其封装成接口的形式,无论是中国人还是英国人都会说话,因此都去实现了这个接口
* 然后通过一个普通类去搭建接口和实现类之间的关系,将接口所声明的变量作为形参,在主方法中通过调用这个类的方法传入实现类的对象去实现一个接口的回调,继而去展现出多态
* 然后下面,我又使用了匿名内部类的形式去直接重写了这个接口中的抽象方法,从运行结果可以看出,也能呈现出同样的效果
* 最后一种,则是对匿名内部类做一个简化操作,这就要使用到我们上面所提到的Lambda表达式了,具体规则不细讲,如果有点遗忘的话可以再翻上去看看


### 新能源时代【⭐⭐⭐】



> 
> 很夸张的一个标题,突然脑洞打开想到的,哈哈,和项目也是有一些联系🔒
> 
> 
> 


上代码



public abstract class MotorVehicles {
abstract void brake(); //刹车功能
}



public interface ControlTemperature { //控制温度
void controlAirTemperature();
}



public interface MoneyFare { //收取费用
void charge();
}



public class Bus extends MotorVehicles implements MoneyFare{
@Override
void brake() {
System.out.println(“公交车正在刹车”);
}

@Override
public void charge() {
    System.out.println("公交车正在计费");
}

}



public class Taxi extends MotorVehicles implements MoneyFare,ControlTemperature{
@Override
void brake() {
System.out.println(“出租车正在刹车”);
}

@Override
public void charge() {
    System.out.println("出租车正在计费");
}

@Override
public void controlAirTemperature() {
    System.out.println("出租车正在调节空调温度");
}

}



public class Cinema implements MoneyFare,ControlTemperature{
@Override
public void charge() {
System.out.println(“电影院开始收费”);
}

@Override
public void controlAirTemperature() {
    System.out.println("电影院正在调节室内温度");
}

}



public class test {
public static void main(String[] args) {
//1.三个类定义对象
Bus bus = new Bus();
Taxi taxi = new Taxi();
Cinema cinema = new Cinema();

    //2.两个接口声明对象
    MoneyFare moneyFare;
    ControlTemperature controlTemperature;

    moneyFare = bus;
    bus.brake();
    moneyFare.charge();

    System.out.println("--------");

    controlTemperature = taxi;
    moneyFare = taxi;
    taxi.brake();
    moneyFare.charge();
    controlTemperature.controlAirTemperature();

    System.out.println("--------");
    
    moneyFare = cinema;
    controlTemperature = cinema;
    moneyFare.charge();
    controlTemperature.controlAirTemperature();

    //上述操作有体现接口回调
}

}



> 
> ![在这里插入图片描述](https://img-blog.csdnimg.cn/2c87c66916e4442dacd314f4ec09ba11.jpeg#pic_center)
> 
> 
> 


* 这个项目,很明显比上一个小项目稍微复杂了一些,进一步地带大家理解接口,区分接口与抽象类之间的关系,明白接口为什么可以弥补多继承的缺口
* 首先定义了一个机动车抽象类,里面含有一个刹车方法,对于公交车、出租车都是属于机动车,所以应该让这两个类去继承机动车这个父类,而且他们都可以有【刹车】这一个功能,**但是对于电影院类,则不属于机动车,只是一个独立与机动车类族的一个单独类**,但是对于【控制温度】和【收取费用】这两个功能电影院也是需要有,可是呢,电影院不会刹车呀,比如放一些爱情片你说怎么刹车,就这么放下去了,管你下面有没有小孩(🐶)
* 难道为此再去定义一个抽象类例如多功能电影院吗,这如果实在我们这种小项目是没关系,但如果这个场景放在实际企业开发中,新定义一个抽象类这种行为是具有风险性的,因为随着抽象类的增加,就需要重新构建上层类族之间的关系,就会使得整个项目的框架逻辑变得更加复杂,这种想到增加功能就去多写一个抽象类的行为是不可取的,
* 因此我们就想到了接口这个东西,我们可以将收取费用和控制空调温度封装到一个功能接口中,或者分开定义也可以。这样的话,影院就不需要去继承机动车类,而是只需要实现这两个接口即可
* 对于主方法中的一些操作,我都清晰地将每个类分割开来,通过接口所声明的变量去接收实现类的对象,继而去呈现一个接口的回调,从运行结果也可以很清晰地看出


### 疯狂农场【⭐⭐⭐⭐⭐】



> 
> 首先声明,这个项目不是我的,是从一位大佬那里拿来的,我将其重新实现做一个讲解,这是他的[博客链接]( ),大家可以去看看
> 
> 
> 


上代码



public abstract class Animal {
public abstract String getName();
public abstract void move(String destination);
public abstract void drink();
}



public abstract class Mammal extends Animal{
}



public abstract class Reptile extends Animal{
}



public interface Huntable { //泛型接口
//不仅是动物可以捕猎,其他生物也是可以捕猎(增加了广泛性)
void hunt(T o);

public default int max(int a,int b){
    return a > b ? a : b;
}

}



public class Tiger extends Mammal implements Huntable{
private String name = “Tiger”;

@Override
public String getName() {
    return this.name;
}

@Override
public void move(String destination) {
    System.out.println(name + " move to the " + destination);
}

@Override
public void drink() {
    System.out.println("Tiger lower it's head and drinks");
}

@Override
public void hunt(Animal animal) {
    System.out.println("Tiger catched the " + animal.getName() + " and eat it");
}

}



public class Goat extends Mammal{
private String name = “Goat”;

@Override
public String getName() {
    return this.name;
}

@Override
public void move(String destination) {
    System.out.println(name + " move to the " + destination);
}

@Override
public void drink() {
    System.out.println("Goat lower it's head and drinks");
}

}



public class Rabbit extends Mammal{
private String name = “Rabbit”;

@Override
public String getName() {
    return this.name;
}

@Override
public void move(String destination) {
    System.out.println(name + " move to the " + destination);
}

@Override
public void drink() {
    System.out.println("Rabbit put out it's tongue and drinks");
}

}



public class Snake extends Reptile implements Huntable{
private String name = “Snake”;

@Override
public String getName() {
    return this.name;
}

@Override
public void move(String destination) {
    System.out.println(name + " move to the" + destination);
}

@Override
public void drink() {
    System.out.println(name + "dived into water and drinks");
}

@Override
public void hunt(Animal animal) {
    System.out.println("Snake catched the " + animal.getName() + " and eat it");
}

}



public class Farmer {
public void BringWater(String desination)
{
System.out.println("Farmer bring the water to the " + desination);
}

public void FeefWater(Animal animal)
{
    BringWater("Farm");
    animal.move("Farm");
    animal.drink();
    System.out.println("----------");
}

public void work()
{
    Farmer farmer = new Farmer();
    Tiger tiger = new Tiger();
    Goat goat = new Goat();
    Rabbit rabbit = new Rabbit();

    farmer.FeefWater(tiger);
    farmer.FeefWater(goat);
    farmer.FeefWater(rabbit);
}

public void BringAnimal(Animal animal,String desination)
{
    System.out.println("Farmer bring the " + animal.getName() + " to the " + desination);
}

// public void FeedAnimal(Animal hunter,Animal prey)
// {
// BringAnimal(prey,“Farm”);
// hunter.move(“Farm”);
// Huntable huntable = (Huntable) hunter;
// huntable.hunt(prey);
// System.out.println(“----------”);
// }

public void FeedAnimal(Huntable huntable,Animal prey)
{
    BringAnimal(prey,"Farm");
    Animal animal = (Animal) huntable;
    animal.move("Farm");        //多态
    huntable.hunt(prey);                  //接口回调
    System.out.println("----------");
}

}



public class test {
public static void main(String[] args) {
Farmer farmer = new Farmer();

    farmer.work();

    Tiger tiger = new Tiger();

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!

" + animal.getName() + " to the " + desination);
}

// public void FeedAnimal(Animal hunter,Animal prey)
// {
// BringAnimal(prey,“Farm”);
// hunter.move(“Farm”);
// Huntable huntable = (Huntable) hunter;
// huntable.hunt(prey);
// System.out.println(“----------”);
// }

public void FeedAnimal(Huntable huntable,Animal prey)
{
    BringAnimal(prey,"Farm");
    Animal animal = (Animal) huntable;
    animal.move("Farm");        //多态
    huntable.hunt(prey);                  //接口回调
    System.out.println("----------");
}

}



public class test {
public static void main(String[] args) {
Farmer farmer = new Farmer();

    farmer.work();

    Tiger tiger = new Tiger();

[外链图片转存中…(img-meUnqQKA-4702043911717)]
[外链图片转存中…(img-GAGAI381-4702043911718)]
[外链图片转存中…(img-y4iAlU8M-4702043911718)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!

  • 25
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值