Java面向对象基础

Java 基础问题汇总

什么是面向对象编程,Java类和对象有什么区别#

OOP(Object Oriented Programming)编程是利用“类”和“对象”来创建模型实现对真实世界的描述

  • 使程序更加容易扩展和易修改,使开发效率变得更高。
  • 基于面向对象的程序可以使他人更加容易理解你的代码逻辑

类和对象的区别:

  • 类是对象的抽象,而对象是类的具体实例;类是现实世界或思维世界中的实体模板,而对象是具体实例

OOP的三大特性即核心思想#

面向对象的本质是抽象。从面对的问题域抽象出解决问题所需的对象是面向对象方法的核心思想。能否恰当抽象出足够的对象类型,特别是抽象出潜在的对象是决定软件设计好坏的关键。如果从更宽泛的角度讲,对我们所面对的复杂问题进行抽象,抓住本质,得出高度精炼的逻辑模型,对问题的求解具有重要的意义。从这个角度来说,抽象并不仅仅局限于对象的抽象,也包括流程和更高层的系统结构;而封装、继承、多态是面向对象的基本特征

Java的三大特性

  • 封装:把客观事物封装成抽象的类, 类可以选择把自己的数据和方法只让可信任的类进行操作, 对不可信的进行隐藏

    类 = 数据 + 操作

    通过封装, 对象对内部数据和操作进行不同程度的保护, 以防止其他操作意外地改变或错误地使用对象的数据和操作, 发生我们预想之外的非安全操作.

  • 继承:通过继承可以使用现有类的所有数据和操作, 并且可以对现有类进行扩展.

    被继承的类被称为: 父类 / 基类 / 超类

    实现继承的类被称为: 子类 / 派生类*

    继承的实现方式有两种:

    • 接口继承
      接口继承仅使用接口的属性和方法, 但是子类必须提供其具体实现
    • 类继承
      类继承直接使用现有类的属性和方法而无需提供其具体实现

    组合也是继承一种, 但有点不太容易理解.
    如果对象的变量或者类变量引用了一个对象, 那么我们也就拥有了该对象对外开放的属性和方法, 也可以说间接的"继承或者说"拥有了"该类的属性和方法.

  • 多态:多态是指一个对象的相同方法在不同的情形有不同的表现形式.
    多态使得不同内部结构的对象可以共享相同的外部接口.

    多态的常见表现形式:

    • 类实现了接口, 将该类传入接口参数.
    • 类继承了父类, 将该类传入父类参数.

    很多人认为重载是多态的一种, 但我认为不是, 面向对象的多态是一种运行时的特征, 而不是编译期的特征

Java抽象类和接口的异同点#

  • 抽象类:抽象类是用来管理一些抽象内容的类

    1. 抽象类和抽象方法必须用abstact关键字来修饰。
    2. 抽象方法定义时,只需要声明,不需要实现
    3. 含抽象方法的类必须被声明为抽象类
    4. 抽象类的子类必须实现所有的抽象方法后,才能被实例化,若不想实现抽象方法,就定义它为抽象类,否则会报错。
    5. 不能被实例化
  • 接口:接口(interface)就是定义一套方法/规则,用于对象之间的通信

    1. 可以定义内部类

    2. 不能定义变量

    3. 不能定义代码块

    4. 不能添加普通/对象/实例方法

    5. 不能定义构造方法,只有抽象方法,java8后允许接口的默认实现

    6. 使用implements实现一个接口

    7. 默认的变量都是static final 常量

    8. 一个类可以实现多个接口,一个接口可以继承多个接口

JVM,JRE,JDK的区别和关系#

JDK(Java Development Kit,Java开发工具包) ,是整个JAVA的核心,包括了Java运行环境JRE(Java Runtime Envirnment),一堆Java工具(javac/java/jdb等)和Java基础的类库

),包含JVM标准实现及Java核心类库。

JRE(Java Runtime Environment Java运行环境) ,是 JDK 的子集,也就是包括 JRE 所有内容,以及开发应用程序所需的编译器和调试器等工具。

JVM(Java Virtual Machine,Java虚拟机), 是JRE的一部分。它是整个Java实现跨平台的最核心的部分,负责解释执行字节码文件,是可运行Java字节码文件的虚拟计算机

Java 常用判断 ”==“ 和 ”equals“的区别,从内存的方向解释#

  1. == 比较的是变量(栈)内存中存放的对象的(堆)内存地址,用来判断两个对象的地址是否相同,即是否是指相同一个对象。比较的是真正意义上的指针操作
  2. equals用来比较的是两个对象的内容是否相等,由于所有的类都是继承自java.lang.Object类的,所以适用于所有对象,如果没有对该方法进行覆盖的话,调用的仍然是Object类中的方法,而Object中的equals方法返回的却是==的判断,也可以重写equals方法比较字符是否相等,String类就从写equals方法来实现字符串比较

什么是值传递,什么是引用传递#

  • 值传递: 是指在调用方法时,将实际参数拷贝一份传递给方法,这样在方法中修改形式参数时,不会影响到实际参数。
  • 引用传递: 也叫地址传递,是指在调用方法时,将实际参数的地址传递给方法,这样在方法中对形式参数的修改,将影响到实际参数。
  • 也就是说值传递,传递的是副本。引用传递,传递的是实际内存地址。这是两者的本质区别

什么是深拷贝,什么是浅拷贝,常用的实现方式#

  • 浅拷贝:浅拷贝是会将对象的每个属性进行依次复制,但是当对象的属性值是引用类型时,实质复制的是其引用,当引用指向的值改变时也会跟着变化

  • 深拷贝:深拷贝复制变量值,对于引用数据,则递归至基本类型后,再复制

    实现方式:

    • 序列化
    • 重写对象clone()方法

Java 常见的四种引用关系即作用范围#

  1. 强引用:类似Object obj = new Object( )这类的引用,只要强引用存在,垃圾收集器永远不会回收掉被引用的对象

  2. 软引用:描述一些还有用,但并非必需的对象。对于软引用关联的对象,在系统第一次gc时,将会把这些对象列进回收范围之中,以便进行第二次回收,第二次回收的时候就会将软引用关联的对象进行回收。SoftReference类来实现软引用;软引用适合缓存使用的场景

  3. 弱引用:也是用来描述非必需对象的,但是它的强度比软引用更弱一些。只被弱引用关联的对象,当垃圾收集器工作时,无论当前内存是否足够,都会回收掉被弱引用关联的对象。WeakReference类来实现软引用。

  4. 虚引用:也称为幽灵引用或者幻影引用,它是最弱的引用关系。无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。PhantomReference类来实现虚引用。

    Java堆中保存的直接内存的引用,就是虚引用的使用场景,在垃圾回收虚引用关联的内存的时候,此虚引用关联的直接内存,会收到内存被回收的信息,进而对直接内存进行清理工作

Java反射机制和语法,泛型和类型擦除的概念#

什么是反射:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制

方法名 功能说明
forName(String name) 返回指定类名 name 的 Class 对象
newInstance() 调用缺省构造函数,返回该Class对象的一个实例
newInstance(Object []args) 调用当前格式构造函数,返回该Class对象的一个实例
getName() 返回此Class对象所表示的实体(类、接口、数组类、基本类型或void)名称
getSuperClass() 返回当前Class对象的父类的Class对象
getInterfaces() 获取当前Class对象的接口
getClassLoader() 返回该类的类加载器
getSuperclass() 返回表示此Class所表示的实体的超类的Class
getFields() 获取类中public类型的属性
getField(String name) 获取类特定的方法,name参数指定了属性的名称
getDeclaredFields() 获取类中所有的属性(public、protected、default、private),但不包括继承的属性
getDeclaredField(String name) 获取类特定的方法,name参数指定了属性的名称
getConstructors() 获取类中的公共方法
getConstructor(Class[] params) 获取类的特定构造方法,params参数指定构造方法的参数类型
getDeclaredConstructors() 获取类中所有的构造方法(public、protected、default、private)
getDeclaredConstructor(Class[] params) 获取类的特定构造方法,params参数指定构造方法的参数类型
getMethods() 获得类的public类型的方法
getMethod(String name, Class[] params) 获得类的特定方法,name参数指定方法的名字,params参数指定方法的参数类型
getDeclaredMethods() 获取类中所有的方法(public、protected、default、private)
getDeclaredMethod(String name, Class[] params) 获得类的特定方法,name参数指定方法的名字,params参数指定方法的参数类型

泛型信息只存在于代码编译阶段,但是在java的运行期(已经生成字节码文件后)与泛型相关的信息会被擦除掉,专业术语叫做类型擦除

Java逃逸分析技术#

逃逸分析的基本行为就是分析对象动态作用域:当一个对象在方法中被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他地方中,称为方法逃逸

  • 同步省略:在动态编译同步块的时候,JIT编译器可以借助逃逸分析来判断同步块所使用的锁对象是否只能够被一个线程访问而没有被发布到其他线程。

    如果同步块所使用的锁对象通过这种分析被证实只能够被一个线程访问,那么JIT编译器在编译这个同步块的时候就会取消对这部分代码的同步。这个取消同步的过程就叫同步省略,也叫锁消除

  • 标量替换:在JIT阶段,如果经过逃逸分析,发现一个对象不会被外界访问的话,那么经过JIT优化,就会把这个对象拆解成若干个其中包含的若干个成员变量来代替。这个过程就是标量替换

  • 栈上分配:在Java虚拟机中,对象是在Java堆中分配内存的,这是一个普遍的常识。但是,有一种特殊情况,那就是如果经过逃逸分析后发现,一个对象并没有逃逸出方法的话,那么就可能被优化成栈上分配

Java注解的基本实现,元注解和自定义注解的角度;JDK自带的注解有哪些#

  • @Documented:

    @Documented 注解表明这个注解应该被 javadoc工具记录. 默认情况下,javadoc是不包括注解的. 但如果声明注解时指定了 @Documented,则它会被 javadoc 之类的工具处理, 所以注解类型信息也会被包括在生成的文档中,是一个标记注解,没有成员

  • @Inherited:

    @Inherited 用于表示某个被标注的注解是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类

  • @Target:

    用于描述注解的范围,即注解在哪用。它说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)等。取值类型(ElementType)有以下几种:

    1. CONSTRUCTOR:用于描述构造器
    2. FIELD:用于描述域即类成员变量
    3. LOCAL_VARIABLE:用于描述局部变量
    4. METHOD:用于描述方法
    5. PACKAGE:用于描述包
    6. PARAMETER:用于描述参数
    7. TYPE:用于描述类、接口(包括注解类型) 或enum声明
    8. TYPE_PARAMETER:1.8版本开始,描述类、接口或enum参数的声明
    9. TYPE_USE:1.8版本开始,描述一种类、接口或enum的使用声明
  • @Retention

    用于描述注解的生命周期,表示需要在什么级别保存该注解,即保留的时间长短。取值类型(RetentionPolicy)有以下几种:

    1. SOURCE:在源文件中有效(即源文件保留)
    2. CLASS:在class文件中有效(即class保留)
    3. RUNTIME:在运行时有效(即运行时保留)

从程序运行的角度解析一个main方法#

在JVM实现中,线程为Execution Engine的一个实例,main函数是JVM指令执行的起点,JVM会创建main线程来执行main函数,以触发JVM一系列指令的执行,真正地把JVM run起来。在创建main线程时,会为其分配私有的PC Register、JVM Stack、Native Method Stack,然后进行类加载解析链接等过程

什么是字节码?采用字节码的好处是什么?#

字节码是一种中间代码,它是Java程序编译后生成的一种低级形式的二进制指令集,可以被Java虚拟机(JVM)解释执行。字节码通常以.class文件格式存储在磁盘上,并由JVM在运行时加载和执行。

采用字节码的好处有:

  1. 平台无关性:字节码是与具体平台无关的,同一个字节码可以在任何支持Java虚拟机的平台上运行。

  2. 安全性:Java字节码可以通过安全检查来防止恶意代码的执行,从而提供更高的安全性。

  3. 高效性:字节码是高度优化的机器码,因为它是由Java编译器生成的,这意味着它比解释代码更快。

  4. 动态性:由于Java字节码可以在运行时动态生成,因此可以实现一些动态编程技术,如动态代理和反射等。

  5. 可移植性:由于字节码是可移植的,开发人员可以将其部署到任何支持Java虚拟机的平台上,而不需要担心平台特定的问题。

字节码的结构的增强#

https://pdai.tech/md/java/jvm/java-jvm-class.html
class文件本质上是一个以8位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑的排列在class文件中。jvm根据其特定的规则解析该二进制数据,从而得到相关信息
常用的字节码增强技术:
ASM(Java字节码操控框架):ASM 是一个基于 Java 字节码操纵框架,可以用于在类加载过程中动态生成字节码,也可以用于对现有字节码进行修改。
Javassist:Javassist 是一个开源的字节码编辑库,它提供了一种更简单的方式来编辑字节码,相比 ASM 更加易用。
CGLIB:CGLIB 是一个功能强大的字节码增强库,它可以用来创建动态代理、实现 AOP 等功能。
ByteBuddy:ByteBuddy 是一个相对较新的字节码增强库,它提供了一个简单而强大的 API 来创建和修改 Java 字节码

Instrumentation(javaAgent) 是 Java 的一个内置 API,它允许在类加载时对字节码进行修改和操作。通过 Instrumentation,开发人员可以在类加载时动态地修改类的字节码,以实现诸如性能监控、代码注入、AOP 等功能。
Instrumentation API 主要提供了以下几个核心方法:
premain(String agentArgs, Instrumentation inst):这是一个 Java Agent 的入口方法,可以在 Java 程序启动时被调用,用来注册一个 Java Agent。
agentmain(String agentArgs, Instrumentation inst):这是另一个 Java Agent 的入口方法,它允许在 Java 虚拟机已经启动后动态地加载一个 Java Agent。
addTransformer(ClassFileTransformer transformer):用于向 Instrumentation 注册一个自定义的类转换器,通过这个转换器可以在类加载时修改类的字节码。
retransformClasses(Class<?>... classes):允许在运行时重新转换指定的类,即重新加载类的字节码,这可以用于在运行时动态修改类的行为。

标识符的命名规则#

在Java中,标识符是用来命名变量、方法、类等程序实体的名称。Java中的标识符命名规则如下:

  1. 只能由字母、数字、$和_组成。
  2. 第一个字符必须是字母、$或_,不能是数字。
  3. 标识符大小写敏感。
  4. 名称不能与Java关键字相同。
  5. 建议使用驼峰命名法,即将单词首字母大写,多个单词之间没有分隔符,例如:firstName。
  6. 类名应以大写字母开头,方法名和变量名应以小写字母开头,常量名应全部大写。
  7. 标识符长度没有限制,但一般建议不要太长,易于阅读和理解。

示例合法标识符:

int age;
String userName;
double $rate;
boolean _isValid;

示例非法标识符:

int 1age; //不能以数字开头
String user-name; //不能包含连字符
double rate$; //不能以$结尾
float class; //不能和关键字重名

面向对象和面向过程的区别#

面向对象编程(Object-Oriented Programming,简称OOP)和面向过程编程(Procedural Programming)是两种不同的编程范式。

面向对象编程主要有以下特点:

  1. 封装性:将数据和相关操作封装在一起,以便于控制访问和保护数据的完整性。
  2. 继承性:通过继承可以减少代码重复、提高代码的复用性和可维护性。
  3. 多态性:允许不同的对象对同一个消息作出不同的响应,实现更加灵活的程序设计。

面向过程编程则主要强调:

  1. 程序由一系列函数或子程序构成,每个函数都是围绕着解决特定问题而设计的。
  2. 程序中的数据通常是公共的,任何地方都可以访问和修改。
  3. 程序执行时按照顺序依次执行,通过控制顺序来达到解决问题的目的。

总的来说,面向对象和面向过程都是有效的编程方法,但面向对象更适合大型项目和复杂系统的开发,因为它具有更好的可维护性、可扩展性和可重用性。

String类为什么定义成 final?#

在Java中,String类被定义为final的。这意味着String对象一旦创建,就不能被修改。主要有以下两个原因:

  1. 不可变性(Immutability):String对象的不可变性可以保证它们在多线程环境下是安全的,而且可以作为缓存键值使用,使得系统的性能得到提升。
  2. 安全性:由于String对象是不可变的,所以在Java中使用String可以避免对字符串的修改导致数据不一致或者安全问题。

另外,将String定义为final还可以在编译器和运行时优化中提供更多的机会,从而提高程序的执行效率和性能。总之,将String定义为final是Java语言设计者考虑到各种方面后的最佳实践之一。

java基本数据类型所占字节数#

类型 存储空间 bit数 取值范围
byte 1字节 1*8 -2^7 ~ 2^7-1 ( 即:-128~127 )
short 2字节 2*8 -2^15 - 2^15-1 ( 即:-32768~32767)
int 4字节 4*8 -2^31 - 2^31-1 ( 即: )
long 8字节 8*8 -2^63 - 2^63-1 ( 即: )
float 4字节 4*8 -2^31 - 2^31-1 ( 即: )
double 8字节 8*8 -2^63 - 2^63-1 ( 即: )
char 2字节 2*8 -2^15 - 2^15-1 ( 即:-32768~32767 )
boolean 1字节 1*8 false、true

Java中的基本数据类型有8种,分别为:

  1. byte(1字节):表示整数,取值范围为-128到127。
  2. short(2字节):表示整数,取值范围为-32768到32767。
  3. int(4字节):表示整数,取值范围为-2147483648到2147483647。
  4. long(8字节):表示整数,取值范围为-9223372036854775808到9223372036854775807。
  5. float(4字节):表示单精度浮点数,取值范围比long还大。
  6. double(8字节):表示双精度浮点数,取值范围为正负1.79769313486231570E+308。
  7. char(2字节):表示Unicode字符,取值范围为0到65535。
  8. boolean(1位):表示布尔值,只有两个取值:true和false。

其中,byte、short、int、long、float、double和char这7种基本数据类型都有对应的包装类,分别为Byte、Short、Integer、Long、Float、Double和Character。这些包装类提供了一些常用的方法,可以方便地进行类型转换和操作。

每种基本数据类型在内存中占用的字节数不同,byte占1字节,short占2字节,int占4字节,long占8字节,float占4字节,double占8字节,char占2字节,boolean占1位。

posted @   糯米๓  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示