先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip1024b (备注Java)
正文
在多态关于形状的代码例子中, 我们发现, 父类 Shape 中的 draw 方法好像并没有什么实际工作, 主要的绘制图形都是由Shape 的各种子类的 draw 方法来完成的. 像这种没有实际工作的方法, 我们可以把它设计成一个 抽象方法(abstract method), 包含抽象方法的类我们称为 抽象类(abstract class)
.
abstract class Shape {
abstract public void draw();
}
- 在 draw 方法前加上 abstract 关键字, 表示这是一个抽象方法. 同时抽象方法没有方法体(没有 { }, 不能执行具体代码).
- 对于包含抽象方法的类, 必须加上 abstract 关键字表示这是一个抽象类.
- 抽象方法:一个方法如果被abstract修饰,那么这个方法就是抽象方法。抽象方法可以没有具体的实现。
同时抽象方法不能被private修饰
,因为一旦被private修饰后,非抽象子类是不能重写父类私有的抽象方法的。
-
包含抽象方法的类称作抽象类,其必须被abstract所修饰,
一个抽象类中可以没有抽象方法,但是如果一个类中有抽象方法,那么这个类一定是抽象类
,其必须被abstract所修饰 -
抽象类不可以被实例化。不能使用例如Shape shape = new Shape();这样的语句
但是不影响抽象类发生向上转型,所以说抽象类不可以被实例化,但是可以发生向上转型
.
-
类内的数据成员,和普通类没有区别,可以包含其他的非抽象方法, 也可以包含字段. 这个非抽象方法和普通方法的规则都是一样的, 可以被重写,也可以被子类直接调用
-
抽象类主要就是用来被继承的.
-
如果一个非抽象类继承了这个抽象类,那么这个类必须重写抽象类当中的抽象方法
。(重要) -
当抽象类A 继承 抽象类B 那么A可以不重写B中的抽象方法,但是一旦A要是再被一个非抽象类c继承,那么c类中一定还要重写A中和B中的抽象方法
.
代码示例:
abstract class A {
abstract public void eat();
public void drink() {
}
}
abstract class C extends A {
abstract public void fly();
}
class b extends C {
@Override
public void eat() {
System.out.println(“eat”);
}
@Override
public void fly() {
System.out.println(“fly”);
}
}
抽象类和抽象方法一定是不能被final修饰的
,因为一旦类被final修饰,便不能继承,方法被final修饰,不能被重写
抽象类不能实例化的目的也就是为了继承和重写,所以两者不能同时使用
-
抽象类实现接口时,可以不需要对接口方法进行重写,即可以重写一部分,不重写一部分
-
抽象类有构造方法,但是不能使用,即不能创建具体的对象
抽象类存在的最大意义就是为了被继承.
抽象类本身不能被实例化, 要想使用, 只能创建该抽象类的子类. 然后让子类重写抽象类中的抽象方法
.
有些同学可能会说了, 普通的类也可以被继承呀, 普通的方法也可以被重写呀, 为啥非得用抽象类和抽象方法呢?
答:确实如此. 但是使用抽象类相当于多了一重编译器的校验.
使用抽象类的场景就如上面的代码, 实际工作不应该由父类完成, 而应由子类完成.
那么此时如果不小心误用成父类了, 使用普通类编译器是不会报错的. 但是父类是抽象类就会在实例化的时候提示错误, 让我们尽早发现问题.
很多语法存在的意义都是为了 “预防出错”, 例如我们曾经用过的 final 也是类似. 创建的变量用户不去修改, 不就相当于常量嘛? 但是加上 final 能够在不小心误修改的时候, 让编译器及时提醒我们.
充分利用编译器的校验, 在实际开发中是非常有意义的
.
在实际开发中
,抽象类的作用也是非常重要的:
抽象类可以降低接口实现类对接口实现过程难度,因为在实际开发中一个接口中可能会有很多接口是使用不到的,当一个非抽象类去继承这个接口的时候,就需要重写这个接口中的所有抽象方法,造成代码冗余,为了避免这种情况的发生,此时就需要抽象类将接口中不需要使用的抽象方法进行重写,将需要使用的抽象方法继承下来.
这样其他类只需要去继承不同的抽象类,依照自己业务的要求去寻找自己所需要的抽象类,然后对抽象类中的抽象方法进行重写就行了,从而降低了接口实现过程中的难度。
=================================================================
接口是抽象类的更进一步. 抽象类中还可以包含非抽象方法, 和字段. 而接口中包含的方法都是抽象方法, 字段只能包含静态常量.
我们直接通过一段代码来进行总结:
1.interface Shape1 {
-
//接口中定义的成员变量都会被默认为常量,由public static final默认进行修饰,所以就算不写public static final也无所谓,
-
int a = 10;
-
public static final String name = “sss”;
-
//接口中的方法几乎都为抽象方法,默认为public abstract进行修饰,所以就算不写public abstract也无所谓
-
void draw();
-
//当然接口中也可以定义非抽象方法,用default关键字即可,default是在java8中引入的关键字,具体可看csdn博客
-
default void drink() {
-
System.out.println("喝水");
-
}
13.}
15.class Cycle1 implements Shape1 {
-
@Override
-
public void draw() {
-
System.out.println("画一个⚪");
-
}
21.}
23.class React1 implements Shape1 {
-
@Override//注解
-
public void draw() {
-
System.out.println("画一个□");
-
}
29.}
31.public class TestMain {
-
public static void fun(Shape1 shape) {
-
shape.draw();
-
}
-
public static void main(String[] args) {
-
//接口也是可以发生向上转型的,前提是一个类必须实现了这个接口
-
//例如下面的代码,因为Cycle1类实现了Shape1这个接口,所以此时接口类型的shape引用可以指向Cycle1类的实例了
-
Shape1 shape = new Cycle1();
-
Shape1 shape1=new React1();
-
shape.draw();
-
shape1.draw();
-
}
44.}
-
使用
interface
定义一个接口 -
接口中的方法一定是抽象方法, 因此可以省略 abstract
-
接口中的方法一定是 public,因此可以省略 public
-
Cycle 使用 implements 继承接口. 此时implements表达的含义不再是 “扩展”, 而是 “实现”
-
在调用的时候同样可以创建一个接口的引用, 对应到一个子类的实例.
-
接口不能单独被实例化.
-
接口当中的方法都是抽象方法
。其默认前缀为public abstract,在书写时是可以省略的,因为编译器默认这个方法就是 public abstract -
抽象类其实可以有具体实现的方法。这个方法是被
default
修饰的(JDK1.8加入的
) -
接口当中
只能包含
静态常量,所有常量的前缀全部默认为public static
final,在书写时是可以省略的,因为编译器默认这个成员变量就是public static final
-
接口当中的成员变量默认是:public static final 成员方法是:public abstract
-
接口是不可以被实例化的
。 Shape shape = new Shape();(不允许
) -
接口和类之间的关系 :
implements(实现)
,当一个非抽象类实现了这个接口且接口中有抽象方法时,则这个类必须重写接口中的抽象方法 -
接口的出现是为了
实现多继承
.一个类可以实现多个接口
。但是只能继承一个父类
-
只要这个类
实现
了该接口,那么就可以进行向上转型
。 -
当然一个接口也可以去
继承(扩展)
多个接口
扩展(extends)与实现(implements)的区别
扩展指的是当前已经有一定的功能了, 进一步扩充功能.
实现指的是当前啥都没有, 需要从头构造出来.
1.我们创建接口的时候, 接口的命名一般以大写字母
I
开头.
2.接口的命名一般使用 “
形容词
” 词性的单词.
3.
阿里编码规范中约定, 接口中的方法和属性不要加任何修饰符号, 保持代码的简洁性
.
不加任何修饰符号的意思就是常量省略public static final ,抽象方法省略前缀public abstract
一个错误的代码:
interface IShape {
// 即便不写public,也是默认为public权限
abstract void draw();
}
class Rect implements IShape {
void draw() {
//权限更加严格了,所以无法覆写。意思就是Rect类中重写draw方法时必须加上public才可以
System.out.println(“□”);
}
}
有的时候我们需要让一个类同时继承自多个父类. 这件事情在有些编程语言通过 多继承 的方式来实现的.
然而 Java 中只支持单继承, 一个类只能 extends 一个父类. 但是可以同时实现多个接口, 也能达到多继承类似的效果. 现在我们通过类来表示一组动物
.
class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
}
另外我们再提供一组接口, 分别表示 “会飞的”, “会跑的”, “会游泳的”.
interface IFlying {
void fly();
}
interface IRunning {
void run();
}
interface ISwimming {
void swim();
}
**接下来我们创建几个具体的动物
猫, 是会跑的.**
class Cat extends Animal implements IRunning {
public Cat(String name) {
super(name);
}
@Override
public void run() {
System.out.println(this.name + “正在用四条腿跑”);
}
}
鱼, 是会游的.
class Fish extends Animal implements ISwimming {
public Fish(String name) {
super(name);
}
@Override
public void swim() {
System.out.println(this.name + “正在用尾巴游泳”);
}
}
青蛙, 既能跑, 又能游(两栖动物)
class Frog extends Animal implements IRunning, ISwimming {
public Frog(String name) {
super(name);
}
@Override
public void run() {
System.out.println(this.name + “正在往前跳”);
}
@Override
public void swim() {
System.out.println(this.name + “正在蹬腿游泳”);
}
}
有一种神奇的动物, 水陆空三栖, 叫做 “鸭子”
class Duck extends Animal implements IRunning, ISwimming, IFlying {
public Duck(String name) {
super(name);
}
@Override
public void fly() {
System.out.println(this.name + “正在用翅膀飞”);
}
@Override
public void run() {
System.out.println(this.name + “正在用两条腿跑”);
}
@Override
public void swim() {
System.out.println(this.name + “正在漂在水上”);
}
}
上面的代码展示了 Java 面向对象编程中最常见的用法: 一个类继承一个父类, 同时实现多种接口.
继承表达的含义是 is - a 语义, 而接口表达的含义是 具有 xxx 特性
.
猫是一种动物, 具有会跑的特性.
青蛙也是一种动物, 既能跑, 也能游泳
鸭子也是一种动物, 既能跑, 也能游, 还能飞
这样设计有什么好处呢? 时刻牢记多态的好处, 让程序猿忘记类型. 有了接口之后, 类的使用者就不必关注具体类型, 而只关注某个类是否具备某种能力
.
例如, 现在实现一个方法, 叫 “散步”
public static void walk(IRunning running) {
running.run();
}
在这个 walk 方法内部, 我们并不关注到底是哪种动物, 只要参数是会跑的,就行,此时需要注意的是这个会跑的前提是这个类必须实现了IRunning接口才可以
//因为此时Cat类实现的是IRunning接口,所以此时可以使用向上转型如下所示,若没有实现IRunning接口,则会报错
IRunning iRunning = new Cat(“猫猫”);
walk(iRunning);
//同样的因为此时Frog类实现的是IRunning接口,所以此时可以使用向上转型如下所示,若没有实现IRunning接口,同样会报错
IRunning iRunning1 = new Frog(“青蛙”);
walk(iRunning1);
接口使用实例(Comparable 接口与Comparator接口)
=================================================================================================
刚才的关于例子比较抽象, 我们再来一个更能实际的例子.
给对象数组排序
给定一个学生类
class Student {
private String name;
private int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
@Override
public String toString() {
return “[” + this.name + “:” + this.score + “]”;
}
}
再给定一个学生对象数组
:
Student[]students=new Student[]{
new Student(“张三”,95),
new Student(“李四”,96),
new Student(“王五”,97),
new Student(“赵六”,92),
};
现对这个对象数组中的元素进行排序(按分数降序)
.
最后
ActiveMQ消息中间件面试专题
- 什么是ActiveMQ?
- ActiveMQ服务器宕机怎么办?
- 丢消息怎么办?
- 持久化消息非常慢怎么办?
- 消息的不均匀消费怎么办?
- 死信队列怎么办?
- ActiveMQ中的消息重发时间间隔和重发次数吗?
ActiveMQ消息中间件面试专题解析拓展:
redis面试专题及答案
- 支持一致性哈希的客户端有哪些?
- Redis与其他key-value存储有什么不同?
- Redis的内存占用情况怎么样?
- 都有哪些办法可以降低Redis的内存使用情况呢?
- 查看Redis使用情况及状态信息用什么命令?
- Redis的内存用完了会发生什么?
- Redis是单线程的,如何提高多核CPU的利用率?
Spring面试专题及答案
- 谈谈你对 Spring 的理解
- Spring 有哪些优点?
- Spring 中的设计模式
- 怎样开启注解装配以及常用注解
- 简单介绍下 Spring bean 的生命周期
Spring面试答案解析拓展
高并发多线程面试专题
- 现在有线程 T1、T2 和 T3。你如何确保 T2 线程在 T1 之后执行,并且 T3 线程在 T2 之后执行?
- Java 中新的 Lock 接口相对于同步代码块(synchronized block)有什么优势?如果让你实现一个高性能缓存,支持并发读取和单一写入,你如何保证数据完整性。
- Java 中 wait 和 sleep 方法有什么区别?
- 如何在 Java 中实现一个阻塞队列?
- 如何在 Java 中编写代码解决生产者消费者问题?
- 写一段死锁代码。你在 Java 中如何解决死锁?
高并发多线程面试解析与拓展
jvm面试专题与解析
- JVM 由哪些部分组成?
- JVM 内存划分?
- Java 的内存模型?
- 引用的分类?
- GC什么时候开始?
JVM面试专题解析与拓展!
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
pring bean 的生命周期
Spring面试答案解析拓展
[外链图片转存中…(img-ZfOtHM1d-1713410306208)]
高并发多线程面试专题
- 现在有线程 T1、T2 和 T3。你如何确保 T2 线程在 T1 之后执行,并且 T3 线程在 T2 之后执行?
- Java 中新的 Lock 接口相对于同步代码块(synchronized block)有什么优势?如果让你实现一个高性能缓存,支持并发读取和单一写入,你如何保证数据完整性。
- Java 中 wait 和 sleep 方法有什么区别?
- 如何在 Java 中实现一个阻塞队列?
- 如何在 Java 中编写代码解决生产者消费者问题?
- 写一段死锁代码。你在 Java 中如何解决死锁?
高并发多线程面试解析与拓展
[外链图片转存中…(img-aTHR0rQB-1713410306208)]
jvm面试专题与解析
- JVM 由哪些部分组成?
- JVM 内存划分?
- Java 的内存模型?
- 引用的分类?
- GC什么时候开始?
JVM面试专题解析与拓展!
[外链图片转存中…(img-3FafSdH7-1713410306208)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-PnHmv6p1-1713410306209)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!