技术学习总结
学习技术一定要制定一个明确的学习路线,这样才能高效的学习,不必要做无效功,既浪费时间又得不到什么效率,大家不妨按照我这份路线来学习。
最后面试分享
大家不妨直接在牛客和力扣上多刷题,同时,我也拿了一些面试题跟大家分享,也是从一些大佬那里获得的,大家不妨多刷刷题,为金九银十冲一波!
// 私有化构造器是为了保证不能在类的外部创建其对象,否则就不能确定对象的个数
private Season2(String seasonName, String seasonDesc){
this.seasonName=seasonName;
this.seasonDesc=seasonDesc;
}
//其他需求:获取枚举类对象的属性
//只需要提供属性的get方法即可,但是不能提供set方法,而且也不允许提供set方法,因为枚举类是不可变的常量类,不能被修改
public String getSeasonName() {
return seasonName;
}
public String getSeasonDesc() {
return seasonDesc;
}
//重写show()方法,与普通类实现接口一样,没有任何区别
@Override
public void show() {
System.out.println(“一年四季:春夏秋冬”);
}
}
public class SeasonTest {
public static void main(String[] args) {
Season2 spring = Season2.SPRING;
spring.show();
Season2 summer = Season2.SUMMER;
summer.show();
Season2 autumn = Season2.AUTUMN;
autumn.show();
Season2 winner = Season2.WINNER;
winner.show();
}
}
运行结果:
情况二:若枚举类的每个枚举对象在调用实现的接口方法时,需要呈现出不同的行为方式,则可以让每个枚举对象分别来实现该方法
public interface Show {
void show();
}
//使用enum关键字定义枚举类
public enum Season2 implements Show{
//1.提供当前枚举类的对象,多个对象之间使用",“隔开,末尾使用”;"结束
//系统默认使用public static final修饰
SPRING(“春天”,“鸟语花香”){
//每个枚举对象分别来实现该方法
@Override
public void show() {
System.out.println(“春天是一个鸟语花香的季节!”);
}
},
SUMMER(“夏天”,“夏日炎炎”){
@Override
public void show() {
System.out.println(“夏天是一个夏日炎炎的季节!”);
}
},
AUTUMN(“秋天”,“秋高气爽”){
@Override
public void show() {
System.out.println(“秋天是一个秋高气爽的季节!”);
}
},
WINNER(“冬天”,“寒风瑟瑟”){
@Override
public void show() {
System.out.println(“冬天是一个寒风瑟瑟的季节!”);
}
};
//2.声明Season对象的属性,又因为枚举类对象的属性不应允许被改动, 所以应该使用 private final修饰
private final String seasonName;
private final String seasonDesc;
//3.枚举类的构造器只能使用 private 权限修饰符
// 私有化构造器是为了保证不能在类的外部创建其对象,否则就不能确定对象的个数
private Season2(String seasonName, String seasonDesc){
this.seasonName=seasonName;
this.seasonDesc=seasonDesc;
}
//其他需求:获取枚举类对象的属性
//只需要提供属性的get方法即可,但是不能提供set方法,而且也不允许提供set方法,因为枚举类是不可变的常量类,不能被修改
public String getSeasonName() {
return seasonName;
}
public String getSeasonDesc() {
return seasonDesc;
}
}
public class SeasonTest {
public static void main(String[] args) {
Season2 spring = Season2.SPRING;
spring.show();
Season2 summer = Season2.SUMMER;
summer.show();
Season2 autumn = Season2.AUTUMN;
autumn.show();
Season2 winner = Season2.WINNER;
winner.show();
}
}
运行结果:
4、枚举类对switch的语句的影响
Java1.5新增enum关键字的同时,也扩大了switch的语句使用范围。Java1.5之前,switch中的值只能是简单数据类型,比如int、byte、short、char, 有了枚举类型之后,就可以使用枚举类的对象了。同时在switch表达式中使用enum定义的枚举类的对象作为表达式时, case子句可以直接使用枚举对象的名字, 无需添加枚举类作为限定。这样一来,程序的控制选择就变得更加的方便,看下面的例子:
public enum WeekDay {
// 定义一周七天的枚举类型
Monday,Tuesday, Wednesday ,Thursday,Friday,Saturday,Sunday;
}
class Test{
public static void getDay(WeekDay weekDay){
switch (weekDay){
case Monday:
System.out.println(“Today is Monday”);
break;
case Tuesday:
System.out.println(“Today is Tuesday”);
break;
case Wednesday:
System.out.println(“Today is Wednesday”);
break;
case Thursday:
System.out.println(“Today is Thursday”);
break;
case Friday:
System.out.println(“Today is Friday”);
break;
case Saturday:
System.out.println(“Today is Saturday”);
break;
case Sunday:
System.out.println(“Today is Sunday”);
break;
default:
System.out.println(“data error”);
}
}
public static void main(String[] args) {
WeekDay sunday = WeekDay.Sunday;
getDay(sunday);
WeekDay friday = WeekDay.Friday;
getDay(friday);
}
}
运行结果:
对于这些枚举的日期,JVM都会在运行期构造成出一个简单的对象实例一一对应。这些对象都有唯一的identity,类似整型数值一样,switch语句就会根据此来identity进行执行跳转。
5、枚举类的线程安全问题
枚举类天生线程就是安全的,下面我们就来进行验证。
先写一个简单的枚举类,还是以季节类为例:
public enum Season {
SPRING,SUMMER,AUTUMN,WINNER;
}
然后我们使用反编译,看看枚举类代码到底是怎么实现的,反编译后的代码内容如下:
public final class zzuli.edu.Season extends java.lang.Enum<zzuli.edu.Season> {
public static final zzuli.edu.Season SPRING;
public static final zzuli.edu.Season SUMMER;
public static final zzuli.edu.Season AUTUMN;
public static final zzuli.edu.Season WINNER;
private static final zzuli.edu.Season[] $VALUES;
public static zzuli.edu.Season[] values();
public static zzuli.edu.Season valueOf(java.lang.String);
private zzuli.edu.Season();
static {};
}
由上述代码可知,每一个枚举类的枚举对象都是被public static final 进行修饰的,又因为被static修饰的属性在类加载的时候就会被加载,而且只会被加载一次,所以枚举类天生就是线程安全的。
6、枚举类实现单例模式
实现单例模式的方法有很多种,但是使用枚举类实现单例模式是最好、最安全的一种方式,这种方式也是Effective Java作者Josh Bloch 提倡的方式。因为它天生线程安全,不仅能避免多线程同步问题,而且还能防止使用反射重新创建新的对象。
使用枚举类实现单例模式非常简单,如下所示:
public enum EnumSingle {
INSTANCE;
public EnumSingle getInstance(){
return INSTANCE;
}
}
下面使用代码进行测试,看创建的对象是否是单例:
public class Test {
public static void main(String[] args) throws NoSuchMethodException {
EnumSingle instance1 = EnumSingle.INSTANCE;
EnumSingle instance2 = EnumSingle.INSTANCE;
System.out.println(instance1==instance2);
}
}
运行结果:
由运行结果可知,成功使用了单例模式。接下来测试使用反射能不能创建新的实例对象。
先来看一下使用反射创建实例对象newInstance方法的源码:
[图片上传失败…(image-8ba546-1633679059670)]
由newInstance方法的源码可知,反射在通过newInstance方法创建对象时,会先检查该类是否是枚举类,如果是,则会抛出IllegalArgumentException(“Cannot reflectively create enum objects”)异常,导致使用反射创建对象失败。下面我们就来测试一下:
先看一下枚举类的源码是有参构造函数还是无参构造函数,编译后的源码如下:
由源码可知,枚举类的构造函数为无参构造函数,下面就使用反射获取枚举类的无参构造函数,看使用反射是否能创建新的实例对象。
public class Test2 {
public static void main(String[] args) throws Exception {
EnumSingle instance1 = EnumSingle.INSTANCE;
Constructor declaredConstructor = EnumSingle.class.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
EnumSingle instance2 = declaredConstructor.newInstance();
System.out.println(instance1);
System.out.println(instance2);
}
}
运行结果:
由运行抛出的异常可知,并不是我们预期的newInstance方法中的IllegalArgumentException(“Cannot reflectively create enum objects”)异常,而是NoSuchMethodException异常,说明枚举类中并没有无参构造函数,编译后的源码欺骗了我们。
接着我们通过javap反编译看一下枚举类的代码
[图片上传失败…(image-182813-1633679059670)]
public final class zzuli.edu.enumTest.EnumSingle extends java.lang.Enum<zzuli.edu.enumTest.EnumSingle> {
public static final zzuli.edu.enumTest.EnumSingle INSTANCE;
private static final zzuli.edu.enumTest.EnumSingle[] $VALUES;
public static zzuli.edu.enumTest.EnumSingle[] values();
public static zzuli.edu.enumTest.EnumSingle valueOf(java.lang.String);
private zzuli.edu.enumTest.EnumSingle();
public zzuli.edu.enumTest.EnumSingle getInstance();
static {};
}
由上述反编译后的枚举类代码可知,反编译后的枚举类中存在的仍然是无参构造函数,说明反编译后的代码仍然骗了我们。下面我们就使用更专业的工具jad来进行反编译。
使用jad反编译后的枚举类源码如下所示:
public final class EnumSingle extends Enum
{
public static EnumSingle[] values()
{
return (EnumSingle[])$VALUES.clone();
}
public static EnumSingle valueOf(String name)
{
return (EnumSingle)Enum.valueOf(zzuli/edu/enumTest/EnumSingle, name);
}
private EnumSingle(String s, int i)
总结
机会是留给有准备的人,大家在求职之前应该要明确自己的态度,熟悉求职流程,做好充分的准备,把一些可预见的事情做好。
对于应届毕业生来说,校招更适合你们,因为绝大部分都不会有工作经验,企业也不会有工作经验的需求。同时,你也不需要伪造高大上的实战经验,以此让自己的简历能够脱颖而出,反倒会让面试官有所怀疑。
你在大学时期应该明确自己的发展方向,如果你在大一就确定你以后想成为Java工程师,那就不要花太多的时间去学习其他的技术语言,高数之类的,不如好好想着如何夯实Java基础。下图涵盖了应届生乃至转行过来的小白要学习的Java内容:
请转发本文支持一下
private EnumSingle(String s, int i)
总结
机会是留给有准备的人,大家在求职之前应该要明确自己的态度,熟悉求职流程,做好充分的准备,把一些可预见的事情做好。
对于应届毕业生来说,校招更适合你们,因为绝大部分都不会有工作经验,企业也不会有工作经验的需求。同时,你也不需要伪造高大上的实战经验,以此让自己的简历能够脱颖而出,反倒会让面试官有所怀疑。
你在大学时期应该明确自己的发展方向,如果你在大一就确定你以后想成为Java工程师,那就不要花太多的时间去学习其他的技术语言,高数之类的,不如好好想着如何夯实Java基础。下图涵盖了应届生乃至转行过来的小白要学习的Java内容:
请转发本文支持一下
[外链图片转存中…(img-INlTHP81-1715238067598)]
[外链图片转存中…(img-ARxHkgQh-1715238067598)]