你的位置:首页 > 信息动态 > 新闻中心
信息动态
联系我们

java基础笔记

2021/10/25 19:23:25

1、什么是面向对象?

“面向对象的方法主要是把事物给对象化,包括其属性和行为。面向对象编程更贴近实际生活的思想。总体来说面向对象的底层还是面向过程,面向过程抽象成类,然后封装,方便使用就是面向对象,(万物皆对象)。”

2、JDK JRE JVM

JVM(JAVA虚拟机)是运行Java字节码的虚拟机,通过编译.java文件为.class文件得到字节码文件 . .class文件包含JVM可以理解的字节码。

在现实世界中,JVM是一种规范,它提供可以执行Java字节码的运行时环境。不同的供应商提供这种规范的不同实现,可访问Different JVM implementations查看

最受欢迎的JVM的实现是Hotspot,它是由Oracle公司拥有并提供维护。

JVM使用许多高级技术为Java程序提供最佳性能,包括 先进的内存模型,GC(垃圾回收器)和adaptive optimizer(自适应优化器)

JVM有两种不同的风格-client和server。虽然Server和Client VMs相似,但是Server VM经过了特殊的调优,可以最大限度地提高峰值运行速度。它用于执行长时间运行的服务器应用程序,这些应用程序需要尽可能快的运行速度,而不是快速启动时间或更小的运行时内存占用。开发人员可以通过指定-client或-server来选择他们想要的系统。

JVM之所以称为虚拟机,是因为它提供了一个不依赖于底层操作系统和机器硬件体系结构的机器接口。

这种与硬件和操作系统的独立性使得Java程序“写一次,到处运行”(write-once-run-anywhere).

Java运行时环境(JRE)是一个软件包,它捆绑了libraries(jar)和JVM,以及用Java编写的应用程序的其他组件。JVM只是JRE发行版的一部分。

执行任何Java程序,需要在机器上安装JRE,这是最低要求。

JRE捆绑的组件如下:

DDL文件:由Java客户端虚拟机使用.
代码库,属性设置,资源文件也都包含,比如rt.jar和charsets.jar
Java扩展文件,如localedata.jar
包含用于安全管理的文件,这些文件包括安全策略(security policy)和安全属性(security properties)
包含applets支持类的jar文件
包含平台使用的TrueType字体文件
JRE可以作为JDK的一部分下载或者也可以单独下载,JRE依赖于平台,这意味着根据机器类型(操作系统和体系结构),必须选择要导入和安装的JRE包
例如:你不能安装64位的JRE到32位的机器上,同样,针对windows的发行版无法在Linux平台中工作.

JDK是JRE的超集,JDK包含了JRE的所有开发,调试和监视应用程序的工具。当要开发Java应用程序时,需要安装JDK.

下面是JDK附带的一些重要组件:

apt 注解处理工具
javadoc 文档生成器,可以自动从源代码生成说明文档
jar 归档器,将相关的类库打包到一个JAR文件中。还可以帮助管理JAR文件
jConsole Java监控和管理平台
jhat Java堆分析工具
jstack 打印Java线程的堆栈信息
keytool 策略创建和管理工具
jarsigner Java签名和验证工具
同JRE,JDK也依赖于平台,所以要下载与机器相对应的JDK包

3、==和equals比较

==可用于基本类型和引用类型:当用于基本类型时候,是比较值是否相同;当用于引用类型的时候,是比较对象是否相同。

对于String a = “a”; Integer b = 1;这种类型的特有对象创建方式,==的时候值是相同的。

基本类型没有equals方法,equals只比较值(对象中的内容)是否相同(相同返回true)。

一个类如果没有定义equals方法,它将默认继承Object中的equals方法,返回值与==方法相同。

4、hashCode与equals

hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode() 定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode() 函数。

通过调用hashCode()方法获取对象的hash值。

equals它的作用也是判断两个对象是否相等,如果对象重写了equals()方法,比较两个对象的内容是否相等;如果没有重写,比较两个对象的地址是否相同,价于“==”。同样的,equals()定义在JDK的Object.java中,这就意味着Java中的任何类都包含有equals()函数。

5、final

在Java中,final关键字可以用来修饰类、方法和变量(包括成员变量和局部变量)。下面就从这三个方面来了解一下final关键字的基本用法。

6、String、StringBuffer、StringBuilder

String 字符串常量
StringBuffer 字符串变量(线程安全)
StringBuilder 字符串变量(非线程安全)

简要的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,那速度是一定会相当慢的。
 而如果是使用 StringBuffer 类则结果就不一样了,每次结果都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,再改变对象引用。所以在一般情况下我们推荐使用 StringBuffer ,特别是字符串对象经常改变的情况下。而在某些特别情况下, String 对象的字符串拼接其实是被 JVM 解释成了 StringBuffer 对象的拼接,所以这些时候 String 对象的速度并不会比 StringBuffer 对象慢,而特别是以下的字符串对象生成中, String 效率是远要比 StringBuffer 快的:
 String S1 = “This is only a” + “ simple” + “ test”;
 StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);
 你会很惊讶的发现,生成 String S1 对象的速度简直太快了,而这个时候 StringBuffer 居然速度上根本一点都不占优势。其实这是 JVM 的一个把戏,在 JVM 眼里,这个
 String S1 = “This is only a” + “ simple” + “test”; 其实就是:
 String S1 = “This is only a simple test”; 所以当然不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的 String 对象的话,速度就没那么快了,譬如:
String S2 = “This is only a”;
String S3 = “ simple”;
String S4 = “ test”;
String S1 = S2 +S3 + S4;
这时候 JVM 会规规矩矩的按照原来的方式去做


在大部分情况下 StringBuffer > String
StringBuffer
Java.lang.StringBuffer线程安全的可变字符序列。一个类似于 String 的字符串缓冲区,但不能修改。虽然在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。
可将字符串缓冲区安全地用于多个线程。可以在必要时对这些方法进行同步,因此任意特定实例上的所有操作就好像是以串行顺序发生的,该顺序与所涉及的每个线程进行的方法调用顺序一致。
StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。
例如,如果 z 引用一个当前内容是“start”的字符串缓冲区对象,则此方法调用 z.append("le") 会使字符串缓冲区包含“startle”,而 z.insert(4, "le") 将更改字符串缓冲区,使之包含“starlet”。
在大部分情况下 StringBuilder > StringBuffer

java.lang.StringBuilde
java.lang.StringBuilder一个可变的字符序列是5.0新增的。此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。两者的方法基本相同。

7、重载(Overload)和重写(Override)的区别

      1. 方法重载

在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同甚至是参数顺序不同)则视为重载。同时,重载对返回类型没有要求,可以相同也可以不同,但不能通过返回类型是否相同来判断重载。

      1. 方法重写

从字面上看,重写就是 重新写一遍的意思。其实就是在子类中把父类本身有的方法重新写一遍。子类继承了父类原有的方法,但有时子类并不想原封不动的继承父类中的某个方法,所以在方法名,参数列表,返回类型(除过子类中方法的返回值是父类中方法返回值的子类时)都相同的情况下, 对方法体进行修改或重写,这就是重写。但要注意子类函数的访问修饰权限不能少于父类的。

8、接口和抽象类的区别

个人理解抽象的本质是为了提取出通用的方法和状态。在通常对类的定义中,类是对象的抽象,是对象的模板,而抽象类也可以理解为对类的抽象,是类的模板。如果一个类中没有足够的信息来描绘一个具体对象,那这个类就可以定义为抽象类。

接口类算是一个特殊的抽象类,它提供统一的协议,体现一种规范,只要实现了接口,就必须实现其中的所有方法。在接口中,不提供具体实现方式。

      1. 抽象类的语法规则:

抽象类介乎于普通类和接口类之间,所以在抽象类中,即能定义抽象方法,也能定义普通方法。定义抽象方法需要加上abstract ,抽象方法是没有方法体的。

抽象类可以有构造方法,接口类没有。如果没有构造方法,那抽象类的子类无法创建对象,那抽象类就毫无意义。

抽象类是不能实例化的,从面向对象思想来看,抽象类本身是对类的抽象,是用于描述类的,并不具备描述对象的能力,所以实例化没意义。从代码运行运行角度来看,如果抽象类可以实例化,又该怎么去调用抽象方法呢?所以抽象类实例化也不可能。

      1. 接口类的语法规则:

接口类中只能定义抽象方法,但是Java8为接口增加了默认方法,默认方法和普通方法一样,只是采用default修饰。实现类也可以调用接口中的默认方法。

接口类中的方法默认是 public abstract 类型,所以在接口类中定义方法省略修饰符。

接口中的成员变量默认是static和final类型的,默认是常量,所以要手动初始化。常量记得全大写。

接口可以继承另一个接口,例如: interface A{ void test(); }  interface B extends A { } ,B接口中可以获得接口A中的所有方法。

9、List和Set的区别

(1)重复对象

list方法可以允许重复的对象,而set方法不允许重复对象

(2)null元素

list可以插入多个null元素,而set只允许插入一个null元素

(3)容器是否有序

list是一个有序的容器,保持了每个元素的插入顺序。即输出顺序就是输入顺序,而set方法是无序容器,无法保证每个元素的存储顺序,TreeSet通过 Comparator 或者 Comparable 维护了一个排序顺序

(4)常用的实现类

list方法常用的实现类有ArrayList、LinkedList 和 Vector。其中ArrayList 最为流行,它提供了使用索引的随意访问,而LinkedList 则对于经常需要从 List 中添加或删除元素的场合更为合适,Vector 表示底层数组,线程安全

Set方法中最流行的几个实现类是 HashSet、LinkedHashSet 以及 TreeSet。最流行的是基于 HashMap实现的 HashSet;TreeSet 还实现了 SortedSet 接口,因此 TreeSet 是一个根据其 compare() 和compareTo() 的定义进行排序的有序容器

10、ArrayList和LinkedList区别

        1. ArrayList是实现了基于动态数组的数据结构,而LinkedList是基于链表的数据结构;

        2. 对于随机访问get和set,ArrayList要优于LinkedList,因为LinkedList要移动指针;

       3. 对于添加和删除操作add和remove,一般大家都会说LinkedList要比ArrayList快,因为ArrayList要移动数据。但是实际情况并非这样,对于添加或删除,LinkedList和ArrayList并不能明确说明谁快谁慢,下面会详细分析。

11、HashMap和HashTable有什么区别?其底层实现是什么?

      1. 1. 区别︰

HashMap方法没有synchronized修饰,线程非安全,HashTable线程安全;

HashMap允许key和value为null,而HashTable不允许

      1. ⒉.底层实现:数组+链表实现

jdk8开始链表高度到8、数组长度超过64,链表转变为红黑树,元素以内部类 Node(链表)节点存在

·计算key的hash值,二次hash然后对数组长度取模,对应到数组下标,

·如果没有产生hash冲突(下标位置没有元素),则直接创建Node存入数组,

·如果产生hash冲突,先进行equal比较,相同则取代该元素,不同,则判断链表高度插入链表,链表高度达到8,并且数组长度到64则转变为红黑树,长度低于6则将红黑树转回链表

. key为null,存在下标0的位置

12、ConcurrentHashMap原理,jdk7和jdk8版本的区别?

      1. jdk7:

数据结构:ReentrantLock+Segment+HashEntry,一个Segment中包含了一个HashEntry数组,每个HashEntry又是一个链表结构。

元素查询:二次hash,第一次hash定位到Segment,第二次hash定位元素所在链表的头部

锁:Segment分段锁,Segment继承了ReentrantLock,锁定操作的Segment,其他Segment不受影响,并发度为Segment的个数,可以通过构造函数指定,数组扩容不影响其他Segment

get方法无须加锁,volatile保证

      1. jdk8:

数据结构:synchronized+CAS+Node+红黑树,Node的val和next都用volatile修饰,保证可见性

查找,替换,赋值操作都使用CAS

锁:锁链表的head节点,不影响其他元素的读写,锁粒度更细,效率更高,扩容时,阻塞所有读写操作,并发扩容

读操作无锁:Node的val和next使用volatile修饰,读写线程对该变量互相可见

数组使用volatile修饰,保证扩容时被读线程感知。

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

      1. 字节码:

Java源代码经过虚拟机编译器编译后产生的文件(即扩展为.class的文件),它不面向任何特定的处理器,只面向虚拟机。

      1. 采用字节码的好处:

Java语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。所以Java程序运行时比较高效,而且,由于字节码并不专对一种特定的机器,因此,Java程序无须重新编译便可在多种不同的计算机上运行。

14、Java中的异常体系

Thorwable类(表示可抛出)是所有异常和错误的超类,两个直接子类为Error和Exception,分别表示错误和异常。其中异常类Exception又分为运行时异常(RuntimeException)和非运行时异常,  这两种异常有很大的区别,也称之为不检查异常(Unchecked Exception)和检查异常(Checked Exception)。下面将详细讲述这些异常之间的区别与联系:

1、Error与Exception
    Error是程序无法处理的错误,它是由JVM产生和抛出的,比如OutOfMemoryError、ThreadDeath等。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。
    Exception是程序本身可以处理的异常,这种异常分两大类运行时异常和非运行时异常。程序中应当尽可能去处理这些异常。
2、运行时异常和非运行时异常
    运行时异常都是RuntimeException类及其子类异常,如NullPointerException、IndexOutOfBoundsException等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
    非运行时异常是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。

Java源代码---->编译器---->jvm可执行的Java字节码(即虚拟指令)---->jvm---->jvm中解释器----->机器可执行的二进制机器码---->程序运行。

15、Java类加载器

      1. JVM三种预定义类型类加载器

当JVM启动的时候,Java开始使用如下三种类型的类加载器:

启动(Bootstrap)类加载器

启动类加载器是用本地代码实现的类加载器,它负责将JAVA_HOME/lib下面的核心类库或-Xbootclasspath选项指定的jar包等虚拟机识别的类库加载到内存中。由于启动类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用。具体可由启动类加载器加载到的路径可通过System.getProperty(“sun.boot.class.path”)查看。

扩展(Extension)类加载器:

扩展类加载器是由Sun的ExtClassLoader(sun.misc.Launcher$ExtClassLoader)实现的,它负责将JAVA_HOME /lib/ext或者由系统变量-Djava.ext.dir指定位置中的类库加载到内存中。开发者可以直接使用标准扩展类加载器,具体可由扩展类加载器加载到的路径可通过System.getProperty("java.ext.dirs")查看。

系统(System)类加载器:

系统类加载器是由 Sun 的 AppClassLoader(sun.misc.Launcher$AppClassLoader)实现的,它负责将用户类路径(java -classpath或-Djava.class.path变量所指的目录,即当前类所在路径及其引用的第三方类库的路径,如第四节中的问题6所述)下的类库加载到内存中。开发者可以直接使用系统类加载器,具体可由系统类加载器加载到的路径可通过System.getProperty("java.class.path")查看。

16、双亲委托模型

Java类加载器(ClassLoader)
双亲委派模式要求除了顶层的启动类加载器外,其余的类加载器都应当有自己的父类加载器,请注意双亲委派模式中的父子关系并非通常所说的类继承关系,而是采用组合关系来复用父类加载器的相关代码,类加载器间的关系如下:

双亲委派模式是在Java 1.2后引入的,其工作原理的是,如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式

    17.GC如何判断对象可以被回收

Java在GC时会看这个对象是否与其他引用有关联,如果存在引用关系则表示这个对象还有用,不能被回收,如果不存在引用关系则可基本定性为可被回收的对象。优点:效率高;缺点:无法解决循环引用的问题。