😎 作者介绍:我是程序员洲洲,一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主。
🤓 同时欢迎大家关注其他专栏,我将分享Web前后端开发、人工智能、机器学习、深度学习从0到1系列文章。
🌼 同时洲洲已经建立了程序员技术交流群,如果您感兴趣,可以私信我加入社群,可以直接vx联系(文末有名片)
🖥 随时欢迎您跟我沟通,一起交流,一起成长、进步!
给大家推荐一个非常好用的求职招聘小程序,秋招、春招、国企、银行都能用:万码优才。
JRE(Java Runtime Environment)
JDK(Java Development Kit)
总结它们的关系:
因此,JDK 包含 JRE,JRE 包含 JVM,JVM 则负责执行 Java 字节码,确保 Java 程序能够跨平台运行。
Java 中有 8 种基本数据类型:
true
或 false
。此外,Java 还有引用数据类型,如数组、类、接口等。
Java 中基本数据类型的转换分为自动类型转换和强制类型转换。以下是它们的详细说明:
自动类型转换(隐式转换)
自动类型转换发生在赋值或表达式中,当源数据类型的范围可以容纳目标数据类型的值时,Java 会自动执行转换。例如,从小范围类型转换到大范围类型时,会自动进行转换。
byte
→ short
→ int
→ long
→ float
→ double
char
→ int
→ long
→ float
→ double
inti =10;longl =i;// 自动转换为 long 类型
强制类型转换(显式转换)
强制类型转换发生在从大范围类型转换到小范围类型时,这时必须显式地进行转换,因为这种转换可能会丢失数据或出现精度问题。
double
→ float
→ long
→ int
→ short
→ byte
doubled =10.5;inti =(int)d;// 强制转换为 int 类型,结果是 10,丢失小数部分
包装类与基本类型的转换
Java 提供了自动装箱和拆箱的功能。自动装箱是指将基本数据类型自动转换为对应的包装类,自动拆箱则是将包装类转换为对应的基本数据类型。
inti =10;Integerinteger =i;// 自动装箱
Integerinteger =10;inti =integer;// 自动拆箱
以上就是 Java 基本数据类型转换的几种方式。
Java 中的基本类型和包装类型有以下区别:
存储方式
int
存储整数值。Integer
存储的是一个 int
类型的值。内存占用
int
占用 4 字节。性能
使用场景
ArrayList
)中,因为集合只能存储对象类型。默认值
int
的默认值为 0,boolean
的默认值为 false
。null
,因为它们是对象类型,未初始化时没有值。自动装箱与拆箱
Integerinteger =10;// 自动装箱inti =integer;// 自动拆箱
基本类型和包装类型各有优缺点,选择时需要根据实际需求权衡性能和功能。
自动装箱和自动拆箱是 Java 中基本类型与包装类型之间的自动转换机制。
自动装箱
自动装箱是指将基本数据类型自动转换为对应的包装类。例如,将 int
类型的值赋给 Integer
类型的对象时,Java 会自动进行转换。
inti =10;Integerinteger =i;// 自动装箱,将基本类型 int 转换为包装类 Integer
自动拆箱
自动拆箱是指将包装类自动转换为对应的基本数据类型。例如,将 Integer
类型的对象赋给 int
类型的变量时,Java 会自动进行转换。
Integerinteger =10;inti =integer;// 自动拆箱,将包装类 Integer 转换为基本类型 int
自动装箱和自动拆箱使得 Java 开发更加简洁,程序员无需显式地进行类型转换,编译器会自动处理这些转换。
成员变量和局部变量在 Java 中有以下几个区别:
定义位置
生命周期
默认值
int
类型默认值为 0
,boolean
默认值为 false
。作用范围
访问修饰符
public
、private
、protected
、default
)来控制访问权限。存储位置
这些区别影响着变量的生命周期、作用范围以及如何在程序中使用。
静态变量是使用 static
关键字定义的变量,属于类而不是类的实例。其主要特点如下:
存储位置
生命周期
共享性
访问方式
MyClass.staticVariable =10;// 使用类名访问MyClassobj =newMyClass();obj.staticVariable =10;// 也可以通过对象访问,但不推荐
默认值
int
类型的默认值为 0
,boolean
为 false
。访问修饰符
public
、private
、protected
或默认访问修饰符来控制其访问权限。用途
静态变量是类的一部分,不依赖于任何对象实例,因此它们对于管理跨多个实例共享的数据非常有用。
在 Java 中,方法参数的传递有两种方式:值传递和引用传递。它们的区别如下:
值传递
publicclassValuePass{ publicstaticvoidmain(String[]args){ intnum =10;modifyValue(num);System.out.println("num after modifyValue: "+num);// 输出 10}publicstaticvoidmodifyValue(intnum){ num =20;// 修改的是 num 的副本}}
modifyValue
方法内部修改了 num
,但原始的 num
变量值没有变化,因为 num
是以值传递的方式传入的。引用传递
publicclassReferencePass{ publicstaticvoidmain(String[]args){ MyClassobj =newMyClass(10);modifyReference(obj);System.out.println("obj.value after modifyReference: "+obj.value);// 输出 20}publicstaticvoidmodifyReference(MyClassobj){ obj.value =20;// 修改的是 obj 的引用所指向的对象}}classMyClass{ intvalue;MyClass(intvalue){ this.value =value;}}
obj
是通过引用传递到 modifyReference
方法的,因此对 obj.value
的修改会影响原始对象的值。适用场景
int
、float
、char
等),因为它传递的是数据副本。总结:
面向对象和面向过程是两种不同的编程范式。它们的主要区别如下:
基本概念
数据和功能的组织方式
代码复用
模块化
代码示例
面向过程:
publicclassProceduralExample{ publicstaticvoidmain(String[]args){ inta =10,b =20;intresult =add(a,b);System.out.println("Sum: "+result);}publicstaticintadd(intx,inty){ returnx +y;}}
在面向过程的例子中,数据(a
和 b
)和操作(add
函数)是分开的,程序执行时通过函数调用进行操作。
面向对象:
publicclassObjectOrientedExample{ publicstaticvoidmain(String[]args){ Calculatorcalc =newCalculator();intresult =calc.add(10,20);System.out.println("Sum: "+result);}}classCalculator{ publicintadd(intx,inty){ returnx +y;}}
在面向对象的例子中,Calculator
类封装了操作和数据,add
方法是类的一部分,数据通过对象(calc
)传递。
灵活性和可维护性
总结:
面向对象的三大特征是封装、继承和多态。它们分别代表了对象如何组织数据、如何实现代码复用以及如何实现动态行为。具体解释如下:
封装
private
、public
)控制对数据的访问。publicclassPerson{ privateStringname;privateintage;// 通过 getter 和 setter 方法访问数据publicStringgetName(){ returnname;}publicvoidsetName(Stringname){ this.name =name;}publicintgetAge(){ returnage;}publicvoidsetAge(intage){ if(age >0){ this.age =age;}}}publicclassTest{ publicstaticvoidmain(String[]args){ Personp =newPerson();p.setName("Alice");p.setAge(30);System.out.println("Name: "+p.getName()+", Age: "+p.getAge());}}
在这个例子中,name
和 age
是私有的,只能通过公共的 getter
和 setter
方法访问,从而实现封装。继承
classAnimal{ publicvoidmakeSound(){ System.out.println("Animal makes a sound");}}classDogextendsAnimal{ publicvoidmakeSound(){ System.out.println("Dog barks");}}publicclassTest{ publicstaticvoidmain(String[]args){ Animalanimal =newDog();animal.makeSound();// 输出 Dog barks}}
在这个例子中,Dog
类继承自 Animal
类,并重写了 makeSound
方法。多态
classAnimal{ publicvoidmakeSound(){ System.out.println("Animal makes a sound");}}classDogextendsAnimal{ publicvoidmakeSound(){ System.out.println("Dog barks");}}classCatextendsAnimal{ publicvoidmakeSound(){ System.out.println("Cat meows");}}publicclassTest{ publicstaticvoidmain(String[]args){ Animalanimal1 =newDog();Animalanimal2 =newCat();animal1.makeSound();// 输出 Dog barksanimal2.makeSound();// 输出 Cat meows}}
在这个例子中,animal1
和 animal2
都是 Animal
类型的引用,但它们实际指向 Dog
和 Cat
对象,因此调用 makeSound
方法时会有不同的输出,这是多态的体现。总结:
多态是面向对象编程中的一项重要特性,指的是同一个方法或操作在不同的对象上表现出不同的行为。多态使得程序更加灵活和可扩展。具体来说,多态可以分为以下几种类型:
方法重写(Override)
classAnimal{ publicvoidsound(){ System.out.println("Animal makes a sound");}}classDogextendsAnimal{ @Overridepublicvoidsound(){ System.out.println("Dog barks");}}classCatextendsAnimal{ @Overridepublicvoidsound(){ System.out.println("Cat meows");}}publicclassTest{ publicstaticvoidmain(String[]args){ AnimalmyAnimal =newAnimal();AnimalmyDog =newDog();AnimalmyCat =newCat();myAnimal.sound();// 输出 "Animal makes a sound"myDog.sound();// 输出 "Dog barks"myCat.sound();// 输出 "Cat meows"}}
在这个例子中,myDog
和 myCat
都是 Animal
类型的引用,但它们分别指向 Dog
和 Cat
对象,因此调用 sound()
方法时会表现出不同的行为。方法重载(Overload)
classCalculator{ publicintadd(inta,intb){ returna +b;}publicdoubleadd(doublea,doubleb){ returna +b;}}publicclassTest{ publicstaticvoidmain(String[]args){ Calculatorcalc =newCalculator();System.out.println(calc.add(10,20));// 输出 30System.out.println(calc.add(10.5,20.5));// 输出 31.0}}
在这个例子中,add
方法根据参数类型的不同,执行不同的操作,这是方法重载。运行时多态和编译时多态
多态的优势
总结:
接口和抽象类是 Java 中两种用于实现抽象行为的机制,尽管它们有一些相似之处,但它们也有很多区别。以下是它们的主要区别:
定义和继承方式
接口:接口是用 interface
关键字定义的,它只能包含抽象方法(JDK 8 以后可以包含默认方法和静态方法)。一个类可以实现多个接口,接口支持多重继承。
抽象类:抽象类是用 abstract class
关键字定义的,它可以包含抽象方法和非抽象方法。一个类只能继承一个抽象类,抽象类支持单继承。
示例:
// 接口定义interfaceAnimal{ voidsound();}// 抽象类定义abstractclassAnimal{ abstractvoidsound();voidsleep(){ System.out.println("Sleeping...");}}
实现的方式
接口:一个类通过 implements
关键字实现接口,并且必须实现接口中的所有抽象方法。
抽象类:一个类通过 extends
关键字继承抽象类,并且可以选择实现抽象类中的某些抽象方法,或者留给子类去实现。
示例:
// 接口实现classDogimplementsAnimal{ @Overridepublicvoidsound(){ System.out.println("Bark");}}// 抽象类继承classDogextendsAnimal{ @Overridevoidsound(){ System.out.println("Bark");}}
构造方法
字段和成员
接口:接口中的字段默认为 public static final
,必须初始化。接口中的方法默认为 public abstract
,并且不能包含实现代码(除非是默认方法或静态方法)。
抽象类:抽象类可以有实例字段,且这些字段不需要是 final
,可以通过构造方法或方法来修改。
示例:
interfaceAnimal{ intage =10;// 接口中的字段默认为 public static finalvoidsound();}abstractclassAnimal{ intage;// 抽象类中的字段可以是实例字段abstractvoidsound();voidsleep(){ System.out.println("Sleeping...");}}
多重继承
使用场景
Animal
,并实现各自的 sound
方法。总结:
在 Java 中,访问权限决定了类、方法、变量等在不同类或包中的可见性。Java 提供了四种访问权限级别:public
、protected
、default
(包私有)和 private
。每种权限的适用范围和访问规则如下:
public
public
访问权限表示该成员可以被任何其他类访问,无论该类在同一包中还是在其他包中。publicclassMyClass{ publicintvalue;publicvoiddisplay(){ System.out.println("Public method");}}
protected
protected
访问权限表示该成员可以在同一包中的其他类或不同包中的子类中访问。protected
不允许不同包中的非子类访问。publicclassMyClass{ protectedintvalue;protectedvoiddisplay(){ System.out.println("Protected method");}}
default(包私有)
classMyClass{ intvalue;// 默认访问权限voiddisplay(){ // 默认访问权限System.out.println("Default method");}}
private
private
访问权限表示该成员只能在定义它的类内部访问,其他类不能访问该成员。publicclassMyClass{ privateintvalue;privatevoiddisplay(){ System.out.println("Private method");}}
总结:
在 Java 中,static
和 final
都是用于修饰类成员的关键字,它们有不同的用途和特性。具体区别如下:
static 关键字
static
用于表示类级别的成员,即该成员属于类本身,而不是类的实例。静态成员可以通过类名访问,不需要创建类的实例。static
可以修饰变量、方法、代码块和嵌套类。静态变量和方法是类级别的,共享给所有对象。classCounter{ staticintcount =0;// 静态变量staticvoidincrement(){ // 静态方法count++;}}publicclassTest{ publicstaticvoidmain(String[]args){ Counter.increment();System.out.println(Counter.count);// 输出 1}}
count
是静态变量,通过类名 Counter
来访问,而无需创建 Counter
的实例。final 关键字
final
用于声明常量、方法和类,表示不可修改。final
用于变量时,表示该变量为常量,初始化后不可修改。final
用于方法时,表示该方法不能被子类重写。final
用于类时,表示该类不能被继承。classMyClass{ finalintMAX_VALUE =100;// 常量finalvoiddisplay(){ // 不能被子类重写System.out.println("Final method");}}publicclassTest{ publicstaticvoidmain(String[]args){ MyClassobj =newMyClass();obj.display();// 输出 "Final method"}}
MAX_VALUE
是常量,不能修改;display
方法是 final
的,不能被子类重写。常见组合
static final
:常常用于声明常量,表示该常量是类级别的,并且不可修改。classMyClass{ staticfinalintMAX_VALUE =100;// 静态常量}publicclassTest{ publicstaticvoidmain(String[]args){ System.out.println(MyClass.MAX_VALUE);// 输出 100}}
MAX_VALUE
是静态常量,可以通过类名直接访问,并且其值不可改变。总结:
final
用于限制修改,确保稳定性。在 Java 中,final
、finally
和 finalize
看起来类似,但它们各自有不同的含义和用途。具体区别如下:
final
final
是一个修饰符,用于声明常量、方法和类。final
用于变量时,表示该变量的值一旦被赋值后就不可更改。final
用于方法时,表示该方法不能被子类重写。final
用于类时,表示该类不能被继承。classMyClass{ finalintMAX_VALUE =100;// 常量finalvoiddisplay(){ // 不能被子类重写System.out.println("Final method");}}
MAX_VALUE
是常量,且不可修改;display
方法是 final
的,不能被子类重写。finally
finally
是用于异常处理中的一个关键字,它定义在 try-catch
语句块之后,表示无论是否发生异常,finally
块中的代码都会被执行。finally
用于执行清理操作,如关闭文件流、释放资源等,确保这些操作不受异常影响。try{ intresult =10/0;}catch(ArithmeticExceptione){ System.out.println("Error: "+e.getMessage());}finally{ System.out.println("Finally block executed");}
finally
块会在 try
或 catch
块执行后始终执行,确保程序的清理工作。finalize
finalize
是 Object
类中的一个方法,它在垃圾回收器准备回收对象时被调用。finalize
方法允许对象在被销毁前执行一些清理操作,但这并不是必须的。finalize
方法已经被标记为过时(deprecated),并且不推荐使用,因为垃圾回收器的行为是非确定性的,不能保证它何时会调用 finalize
方法。classMyClass{ @Overrideprotectedvoidfinalize()throwsThrowable{ System.out.println("Object is being garbage collected");}}publicclassTest{ publicstaticvoidmain(String[]args){ MyClassobj =newMyClass();obj =null;// 使对象变为可回收System.gc();// 强制进行垃圾回收}}
obj
被垃圾回收时,finalize
方法会被调用,但不能确定何时调用。总结:
Object
类中的方法,在垃圾回收时调用,但已不推荐使用。