Java基础知识
面向对象,Java语言特点等
Java
23 views
Oct 08, 2024

#基础概念

##Java语言的特点

  1. 面向对象。封装、多态、继承
  2. 较好的兼容性(Java虚拟机实现跨平台,一次编译,多平台使用)
  3. 支持多线程
  4. 支持网络编程
  5. 编译与解释并从

Write Once, Run Anywhere

##JVM

Java虚拟机,是运行Java字节码的虚拟机。JVM有针对不同系统的特定实现,目的是使用相同的字节码,得到相同的运行结果,是一次编译,处处运行的体现。

##JRE 和 JDK

JDK(Java Development Kit),是全功能的Java SDK。除了包含JRE之外,还有编译器javac,工具javadoc,jdb。

JRE是Java程序运行时的环境,是运行已编译Java程序所需内容的集合。包含JVM,Java类库,Java命令和一些基础构件。正常情况下只需要运行Java程序使用JRE足够,如果需要开发或者编译Java程序则必须使用JDK。

如果使用JSP部署WEB程序,则需要JDK。因为应用程序服务器会将JSP转换为Java Servlet,需要JDK来编译Servlet。

##字节码

JVM可以理解的代码叫做字节码,扩展名为.class的文件。

字节码解决了传统解释型语言执行效率低的问题,同时保留了解释型语言可以值的提点。

##编译与解释并存

编译型:通过编译器一次性将所有代码翻译成机器码。执行速度快但开发效率低。如C、C++、Go、Rust。

解释型:通过解释器一句一句将代码解释成机器码再执行。开发快但执行速度满。如Python,PHP,JS。

Java语言即具有编译型语言的特征,也具有解释型语言的特征。Java程序需要经过先编译,再解释两个过程。

通过编译生成字节码.class文件,再有Java解释器解释执行。

#基础语法

##continue、break 和 return

continue:跳出当前这一次循环,继续执行下一次循环。

break:跳出整个循环体,继续执行循环体下面的代码。

return:天出当前方法,结束该方法的执行。

##成员变量和局部变量

  • 语法形式:成员变量属于类,局部变量属于方法。成员变量可以被public、private、static修饰符修饰,局部变量不行。两者都能被final修饰。
  • 存储方式:如果成员变量被static修饰,这个成员变量属于类,如果没有被static修饰,成员变量属于实例。对象存储与堆中,局部变量存储在栈中。
  • 生存时间;成员变量是对象的一部分,随着对象的创建而创建。局部变量随着方法调用生成,随方法效用结束而结束。
  • 默认值:成员变量如果没有被赋初始值,会自动以类型的默认值赋值(例如boolen默认false,int默认0,string默认null)。局部变量不会自动赋值。

##静态变量

静态变量可以被类的所有实例共享。无论一个类创建了多少个对象,它们都共享同一份静态变量。

通常情况下,静态变量会被 final 关键字修饰成为常量。

##字符常量和字符串常量

  1. 形式 : 字符常量是单引号引起的一个字符,字符串常量是双引号引起的 0 个或若干个字符。
  2. 含义 : 字符常量相当于一个整型值( ASCII 值),可以参加表达式运算; 字符串常量代表一个地址值(该字符串在内存中存放位置)。
  3. 占内存大小 : 字符常量只占 2 个字节; 字符串常量占若干个字节。

##静态方法为什么不能调用非静态成员

静态方法属于类,在类加载时被创建。非静态成员属于实例,当对象被实例化时候创建。

静态方法先于非静态成员创建。

##静态方法和实例方法区别

调用方式:静态方法通过类名.方法名调用。实例方法通过对象.方法名调用。

##重写和重载

重载

只能在同一个类中,方法名必须相同,参数类型、个数、顺序不同,方法返回值,访问修饰符可以不同。

重写

发生在运行时

  1. 方法名,参数列表必须相同,返回类型相同
  2. 如果父类访问修饰符为 private/final/static 则子类就不能重写该方法

#基本数据类型

##8 种数据类型

  • 6 种数字类型
    • 4 种整数型:int\short\byte\long
    • 2 种浮点型:float\double
  • 1 种字符类型:char
  • 1 种布尔型:boolen

##默认值及所占空间大小

基本类型位数字节默认值取值范围
byte810-128 ~ 127
short1620-32768 ~ 32767
int3240-2147483648 ~ 2147483647
long6480L-9223372036854775808 ~ 9223372036854775807
char162'u0000'0 ~ 65535
float3240f1.4E-45 ~ 3.4028235E38
double6480d4.9E-324 ~ 1.7976931348623157E308
boolean11falsetrue、false

long类型需要在数值后加上L,否则将作为整型解析

char a = 'h'char :单引号,String a = "hello" :双引号。

##基本类型和包装类型区别

  • 基本类型的局部变量存放在栈中,基本类型的成员变量存放在堆中。包装类型属于对象,存放在堆中。
  • 包装类型默认值为null。
  • 包装类型可用于泛型,基本类型不可以。

##包装类型的缓存机制

  • Byte,Short,Integer,Long 这 4 种包装类默认创建了数值 -128,127 的相应类型的缓存数据
  • Character 创建了数值在 0,127 范围的缓存数据
  • Boolean 直接返回 True or False
  • Float,Double 没有缓存

如果定义新变量超出范围则会创建新的对象

##拆箱与装箱

  • 装箱:将基本类型用它们对应的引用类型包装起来;
  • 拆箱:将包装类型转换为基本数据类型;

##为什么浮点数运算会丢失精度

无限循环小数在计算机中保存是会被截断,导致小数精度丢失。

##如何解决浮点数精度丢失

使用BigDecimal

##超过lang类型的数据如何表示

使用BigInteger

#面向对象基础

##面向对象和面向过程

  • 面向过程:将问题解决过程拆解成一个个方法,通过一个个方法的执行解决问题。
  • 面向对象:先抽出对象,用对象执行方法的方式解决问题。

##对象实体和对象引用

对象引用:对象的实例化

通过new创建对象实例(对象实例存放在堆中),对象引用指向对象实例(对象引用存放在栈中)。

一个对象引用可以指向0或1个对象。

一个对象可以有n个引用指向它。

##构造方法

完成对象的初始化,在实例化一个对象时,后面的括号说明调用的时无参构造方法。

如果没有声明构造方法,默认会有不带参构造方法。如果声明了有参构造方法,会覆盖默认无参构造方法,需要手动再次声明无参构造方法。

构造方法必须与类名相同,不可以重写,但可重载。

##面向对象的特性,封装、继承、多态

封装

封装是指将一个对象的属性,隐藏在对象内部,不允许外部对象直接访问对象的内部信息。但是可以通过一些允许被外部访问的方法来操作属性方法get(),set()来操作属性。

继承

  • 子类拥有父类所有的属性和方法,但是无法访问父类中私有属性和方法无法访问。
  • 子类可以创建新的属性和方法,对父类进行扩展。
  • 子类可以用自己的方式实现父类的方法。

多态

  • 编译时多态:指方法的重载
  • 运行时多态:程序中定义的对象引用所指向的具体类型在运行期间才确定

多态存在的条件:继承、重写、父类引用指向子类对象(例如:Animal a = new Cat())

##接口和抽象类

相同点:

  1. 不能被实例化
  2. 可以包含抽象方法
  3. 可以有默认的实现方法(使用default关键字在接口中定义默认方法)

不同点:

  1. 单继承,多实现
  2. 接口中成员变量只能是public static final类型的,且必须有初始值。抽象类的成员变量默认default,可以在子类中被重新定义,赋值。

##深拷贝、浅拷贝、引用拷贝

  • 浅拷贝:会在堆上创建一个新的对象,如果原对象内部属性是引用类型的话,浅拷贝会直接地址内部对象的引用地址,即拷贝对象和原对象共用同一个内部对象。
  • 深拷贝:完全复制整个对象,包括这个对象包含的内部对象。
  • 引用拷贝:两个不同的引用指向同一个对象。

image-20220914220308604

#String Object

##==和equals()区别

  • == 判断引用是否指向堆内存的同一块地址
  • equals 比较堆中的内容是否相同,不比较地址

##重写hashCode()必须重写equals()

因为不同对象的hashCode可能相同,但是hashCode不同的对象一定不相同

如果只重写一个,可能会出现equals相同但是hashCode不相同

使用HashSet时,先判断HashCode是否相同,如果相同再使用equals方法判断是否相同。

##String、StringBuffer、StringBuilder

  • StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全。
  • StringBuilder 没有对方法进行加同步锁,所以线程不安全。
  • String不可变(保存字符串的数组被 final 修饰且为私有的),每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象。
  • StringBuffer 每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。

使用:

  1. 操作少量的数据: 适用 String
  2. 单线程操作字符串缓冲区下操作大量数据: 适用 StringBuilder
  3. 多线程操作字符串缓冲区下操作大量数据: 适用 StringBuffer

##字符串拼接不能使用+

如果使用+拼接,实际上是通过StringBuilder调用append()方法实现,拼接之后调用toString()得到String对象。在循环体内使用+拼接时,每循环一次就会创建一个StringBuilder对象,如果手动使用StringBuilder就不会有这个问题。

##String.equals()和 Object.equals()

  • String 中的 equals 方法是被重写过的,比较的是 String 字符串的值是否相等。
  • Objectequals 方法是比较的对象的内存地址。

##字符串常量池

字符串常量池作用是避免重复创建String类导致内存消耗专门开辟的区域。

当创建一个String类型对象时,会将对象的内容保存到堆中,将对象的引用保存到常量池。再次创建相同的String对象时,如果堆中已经有相同的对象,则直接返回常量池中保存的引用。

##String s1 = new String("abc")会创建几个字符串对象

如果字符串 "abc"之前已经创建过了,则会创建 1 个字符串对象。如果字符串"abc"之前未创建,则会创建 2 个字符串对象

##intern 方法

intern 方法将指定的字符串对象的引用保存在字符串常量池

  • 如果字符串常量池中保存了对应的字符串对象的引用,就直接返回该引用。
  • 如果字符串常量池中没有保存了对应的字符串对象的引用,那就在常量池中创建一个指向该字符串对象的引用并返回。

##String 类型的变量和常量做“+”运算

  • 如果是编译期可以确定值的字符串,JVM会将拼接后的字符串引用放入常量池。

例如:String str3 = "str" + "ing"会优化成 String str3 = "string";

  • 如果是编译期间无法确定的字符串, StringBuilder 调用 append() 之后在调用 toString() 得到一个 String

#异常

##Exception 和 Error

Java中主要由两种异常Exception 和 Error。

  • Exception:程序本身可以处理的异常,可以通过catch捕获。Exception有分为Checked Exception受检查异常,必须处理 和 Unchecked Exception不受检查异常,可以不处理
  • Error:程序无法处理的异常,出现Error会导致线程终止。例如Java虚拟机运行异常,内存溢出,堆栈溢出等。

#Checked Exception 和 Unchecked Exception

  • Checked Exception 受检查异常,在编译过程中,如果检查出受检查异常没有被catch或者throws,编译将无法通过。
    • 除了RuntimeException及其子类外,其他Exception都属于受检查异常。
  • Unchecked Exception 不受检查异常,在编译过程中可以不处理。
    • RuntimeException 及其子类都是不受检查异常,常见的有:空指针、数组越界等

##Throwable 类常用方法

  • getMessage()返回异常的简要描述
  • toString()返回异常详细信息
  • getLocalizedMessage()返回异常对象本地化信息
  • printStackTrace()在控制台打印出 Throwable 对象封装的异常信息

#try-catch-finally使用

  • try:用户捕获异常,后必须要接catch或者finally中一个
  • catch:处理try捕获到的异常
  • finally:无论是否捕获到或处理异常,finally都会被执行。如果try或者catch中有return,fianlly会在方法返回之前执行。

##fianlly是否一定会执行

不一定,如果fianlly之前JVM终止运行,fianlly就不会执行,后者程序所在的线程死亡,或者cpu关闭

#泛型

##泛型使用的方式

  • 泛型类
  • 泛型接口
  • 泛型方法

#反射

##什么是反射

在程序运行过程中,动态获取一个对象所属的类,获取类的成员变量和方法,调用类的属性和方法

##什么地方用到了反射

spring通过注解@Component获取到类的信息,属性,参数等。

##如何使用反射获取一个类

  • 通过类名.class
        Class alunbarClass = TargetObject.class;
    
      
  • 通过Class.forName(“类名”)
        Class alunbarClass1 = Class.forName("cn.javaguide.TargetObject");
    
      
  • 通过方法Object.getClass()
        TargetObject o = new TargetObject();
    Class alunbarClass2 = o.getClass();
    
      
  • 通过类加载器xxxClassLoader.loadClass()传入类路径获取:
        ClassLoader.getSystemClassLoader().loadClass("cn.javaguide.TargetObject");
    
      

#注解

##什么是注解

可以修饰类、方法、变量,用于提供信息给程序编译或运行期间使用

##注解解析的方式

  • 编译期间扫描
  • 运行期间通过反射处理

#引用类型

通过引用类型来判断对象是否可以被垃圾回收器回收♻️

##强引用

通过new关键字创建的对象,是强引用,强引用的对象不会被GC回收。

##软引用

软引用对象,会在内存不足时被回收。 通过SoftReference关键字可以创建软引用对象

    Object obj = new Object();
SoftReference<Object> sf = new SoftReference<Object>(obj);

  

##弱引用

弱引用对象会被直接回收,创建的弱引用对象只能存活到下次GC发生之前。 可以通过WeakReference 关键字创建弱引用对象

    Object obj = new Object();
WeakReference<Object> wf = new WeakReference<Object>(obj);

  

##虚引用

不能通过虚引用获取一个对象,虚引用不会对对象产生任何影响。 虚引用的作用是:虚引用的对象被GC回收时可以收到一个通知。 可以通过PhantomReference 关键字创建需引用对象。

    Object obj = new Object();
PhantomReference<Object> pf = new PhantomReference<Object>(obj);

  
Total PV : 0|UV : 0
Current Online:1
From :