java基础(背诵版)(重点)

1.JVM、JRE和JDK的关系?**

1.JVM、JRE和JDK的关系?**

**
**

JVM

Java Virtual Machine是Java虚拟机,Java程序需要运行在虚拟机上,不同的平台有自己的虚拟机,因此Java语言可以实现跨平台。

JRE

Java Runtime Environment包括Java虚拟机和Java程序所需的核心类库等。核心类库主要是java.lang包:包含了运行Java程序必不可少的系统类,如基本数据类型、基本数学函数、字符串处理、线程、异常处理类等,系统缺省加载这个包

如果想要运行一个开发好的Java程序,计算机中只需要安装JRE即可。

JDK

Java Development Kit是提供给Java开发人员使用的,其中包含了Java的开发工具,也包括了JRE。所以安装了JDK,就无需再单独安装JRE了。其中的开发工具:编译工具(javac.exe),打包工具(jar.exe)等

JVM&JRE&JDK关系图

2.Java语言有哪些特点?*

**
**

面向对象(封装,继承,多态)

平台无关性(Java虚拟机实现平台无关性)

支持网络编程并且很方便(Java语言诞生本身就是为简化网络编程设计的)

支持多线程(多线程机制使应用程序在同一时间并行执行多项任)

健壮性(Java语言的强类型机制、异常处理、垃圾的自动收集等)

3.Java 和 C++的区别? ***

**
**

都是⾯向对象的语⾔,都⽀持封装、继承和多态

Java 不提供指针来直接访问内存,程序内存更加安全

Java 的类是单继承的,C++ ⽀持多重继承;虽然 Java 的类不可以多继承,但是接⼝可以多继承。

Java 有⾃动内存管理机制,不需要程序员⼿动释放⽆⽤内存

在 C 语⾔中,字符串或字符数组最后都会有⼀个额外的字符‘\0’来表示结束。但是,Java 语 ⾔中没有结束符这⼀概念。

4.什么是字节码?采用字节码的最大好处是什么?*

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

采用字节码的好处:

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

5.Java基本数据类型图?

6.字符型常量和字符串常量的区别? *

**
**

  1. 形式上: 字符常量是单引号引起的⼀个字符; 字符串常量是双引号引起的若⼲个字符

  2. 含义上: 字符常量相当于⼀个整型值( ASCII 值),可以参加表达式运算; 字符串常量代表⼀个地 址值(该字符串在内存中存放位置)

  3. 占内存⼤⼩ 字符常量只占 2 个字节; 字符串常量占若⼲个字节。

7.访问修饰符 public,private,protected,以及不写(默认)时的区别?**

**
**

Java中,可以使用访问修饰符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。

private : 在同一类内可见。使用对象:变量、方法。注意:不能修饰类(外部类)

default : 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。

protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。注意:不能修饰类(外部类)。

public : 对所有类可见。使用对象:类、接口、变量、方法

访问修饰符图

** **

8.final 有什么用?**

**
**

用于修饰类、属性和方法;

被final修饰的类不可以被继承

被final修饰的方法不可以被重写

被final修饰的变量不可以被改变,被final修饰不可变的是变量的引用,而不是引用指向的内容,引用指向的内容是可以改变的

9.final finally finalize区别?**

final可以修饰类、变量、方法,修饰类表示该类不能被继承、修饰方法表示该方法不能被重写、修饰变量表示该变量是一个常量不能被重新赋值。

finally一般作用在try-catch代码块中,在处理异常的时候,通常我们将一定要执行的代码方法finally代码块中,表示不管是否出现异常,该代码块都会执行,一般用来存放一些关闭资源的代码。

finalize是一个方法,属于Object类的一个方法,而Object类是所有类的父类,该方法一般由垃圾回收器来调用,当我们调用System.gc() 方法的时候,由垃圾回收器调用finalize(),回收垃圾,一个对象是否可回收的,最后判断。

10. 重载和重写的区别?***

重载就是同样的⼀个⽅法能够根据输⼊数据的不同,做出不同的处理

重写就是当⼦类继承⾃⽗类的相同⽅法,输⼊数据⼀样,但要做出有别于⽗类的响应时,你就要覆盖⽗类⽅法

重载:发⽣在同⼀个类中,⽅法名必须相同,参数类型不同、个数不同、顺序不同,与方法返回值和访问修饰符无关,即重载的方法不能根据返回类型进行区分。

重写:发生在父子类中,方法名、参数列表必须相同,返回值小于等于父类,抛出的异常小于等于父类,访问修饰符大于等于父类(里氏代换原则);如果父类方法访问修饰符为private则子类中就不是重写。

11.== 和 equals 的区别 ***

==:对于基本数据类型,==比较的是值;对于引用数据类型,==比较的是内存地址。

Equals:对于没有重写equals方法的类,equals方法和==作用类似;对于重写过equals方法的类,equals比较的是值。

12. hashCode 与 equals***

**
**

Equals:

equals方法首先比较的是内存地址,如果内存地址相同,直接返回true;如果内存地址不同,再比较对象的类型,类型不同直接返回false;类型相同,再比较值是否相同;值相同返回true,值不同返回false。总结一下,equals会比较内存地址、对象类型、以及值,内存地址相同,equals一定返回true;对象类型和值相同,equals方法一定返回true。

如果没有重写equals方法,那么equals和==的作用相同,比较的是对象的地址值。

hashCode

hashCode方法返回对象的散列码,返回值是int类型的散列码。散列码的作用是确定该对象在哈希表中的索引位置。

关于hashCode有一些约定:

  1. 两个对象相等,则hashCode一定相同。

  2. 两个对象有相同的hashCode值,它们不一定相等。

  3. hashCode()方法默认是对堆上的对象产生独特值,如果没有重写hashCode()方法,则该类的两个对象的hashCode值肯定不同

(1) 为什么重写equals方法后,hashCode方法也必须重写)****

为什么重写equals方法后,hashCode方法也必须重写

  1. 根据规定,两个对象相等,hashCode值也许相同,所以重写equals方法后,hashCode方法也必须重写(面试官肯定不是想听这个答案)

  2. hashCode在具有哈希机制的集合中起着非常关键的作用,比如HashMap、HashSet等。以HashSet为例,HashSet的特点是存储元素时无序且唯一,在向HashSet中添加对象时,首相会计算对象的HashCode值来确定对象的存储位置,如果该位置没有其他对象,直接将该对象添加到该位置;如果该存储位置有存储其他对象(新添加的对象和该存储位置的对象的HashCode值相同),调用equals方法判断两个对象是否相同,如果相同,则添加对象失败,如果不相同,则会将该对象重新散列到其他位置。所以重写equals方法后,hashCode方法不重写的话,会导致所有对象的HashCode值都不相同,都能添加成功,那么HashSet中会出现很多重复元素,HashMap也是同理(因为HashSet的底层就是通过HashMap实现的),会出现大量相同的Key(HashMap中的key是唯一的,但不同的key可以对应相同的value)。所以重写equals方法后,hashCode方法也必须重写。同时因为两个对象的hashCode值不同,则它们一定不相等,所以先计算对象的hashCode值可以在一定程度上判断两个对象是否相等,提高了集合的效率。总结一下,一共两点:第一,在HashSet等集合中,不重写hashCode方***导致其功能出现问题;第二,可以提高集合效率。

(2) 为什么要有 hashCode?

我们以“ HashSet 如何检查重复”为例⼦来说明为什么要有 hashCode?当你把对象加⼊ HashSet 时, HashSet 会先计算对象的 hashcode 值来判断对象加⼊的位置, 同时也会与其他已经加⼊的对象的 hashcode 值作⽐᫾,如果没有相符的 hashcode, HashSet 会假设对象没有重复出现。但是如果发现有相同 hashcode 值的对象,这时会调⽤ equals() ⽅ 法来检查 hashcode 相等的对象是否真的相同。如果两者相同, HashSet 就不会让其加⼊操作成功。如果不同的话,就会重新散列到其他位置。

13.Java 中是值传递还是引用传递,还是两者共存 **

这是一个很容易搞混又很难解释清楚的问题,先说结论,Java中只有值传递

先看这样一段代码


public class Main{

public static void main(String[] args) {

    int a = 1;

    printValue(a);

    System.out.println("a:" + a);

}

public static void printValue(int b){

    b = 2;

    System.out.println("b:"+ b);

}

}

输出

1

2

b:2

a:1

可以看到将a的值传到printValue方法中,并将其值改为2。但方法调用结束后,a的值还是1,并未发生改变,所以这种情况下为值传递。

再看这段代码


public class Main{

public static void main(String[] args) {

    Preson p = new Preson();

    p.name = "zhangsan";

    printValue(p);

    System.out.println("p.name: " + p.name);

}

public static void printValue(Preson q){

    q.name = "lisi";

    System.out.println("q.name: "+ q.name);

}

}

class Preson{

public String name;

}

输出结果

1

2

q.name: lisi

p.name: lisi

在将p传入printValue方法后,方法调用结束,p的name属性竟然被改变了!所以得出结论,参数为基本类型为值传递,参数为引用类型为时为引用传递。这个结论是错误的,下面来看看判断是值传递还是值传递的关键是什么,先看定义

· 值传递:是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。

· 引用传递:是指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。

从定义中可以明显看出,区分是值传递还是引用传递主要是看向方法中传递的是实际参数的副本还是实际参数的地址。上面第一个例子很明显是值传递,其实第二个例子中向printValue方法中传递的是一个引用的副本,只是这个副本引用和原始的引用指向的同一个对象,所以副本引用修改过对象属性后,通过原始引用查看对象属性肯定也是被修改过的。换句话说,printValue方法中修改的是副本引用指向的对象的属性,不是引用本身,如果修改的是引用本身,那么原始引用肯定不受影响。看下面这个例子


public class Main{

public static void main(String[] args) {

    Preson p = new Preson();

    p.name = "zhangsan";

    printValue(p);

    System.out.println("p.name: " + p.name);

}

public static void printValue(Preson q){

    q = new Preson();

    q.name = "lisi";

    System.out.println("q.name: "+ q.name);

}

}

class Preson{

public String name;

}

输出结果

1

2

q.name: lisi

p.name: zhangsan

可以看到将p传入printValue方法后,printValue方法调用结束后,p的属性name没有改变,这是因为在printValue方法中并没有改变副本引用q所指向的对象,而是改变了副本引用q本身,将副本引用q指向了另一个对象并对这个对象的属性进行修改,所以原始引用p所指向的对象不受影响。所以证明Java中只存在值传递。

14. Java ⾯向对象编程三⼤特性: 封装 继承 多态 ***

**
**

(1) 封装

封装把⼀个对象的属性私有化,同时提供⼀些可以被外界访问的属性的⽅法,如果属性不想被外界访问,我们⼤可不必提供⽅法给外界访问。

(2) 继承

继承是使⽤已存在的类的定义作为基础建⽴新类的技术,新类的定义可以增加新的数据或新的功能,也可以⽤⽗类的功能,但不能选择性地继承⽗类。通过使⽤继承我们能够⾮常⽅便地复⽤以前的代码。关于继承如下3点请记住:

  1. ⼦类拥有⽗类对象所有的属性和⽅法(包括私有属性和私有⽅法),但是⽗类中的私有属性 和⽅法⼦类是⽆法访问,只是拥有。

  2. ⼦类可以拥有⾃⼰属性和⽅法,即⼦类可以对⽗类进⾏扩展。

  3. ⼦类可以⽤⾃⼰的⽅式实现⽗类的⽅法。(以后介绍)。

(3)多态

所谓多态就是指程序中定义的引⽤变量所指向的具体类型和通过该引⽤变量发出的⽅法调⽤在编 程时并不确定,⽽是在程序运⾏期间才确定,即⼀个引⽤变量到底会指向哪个类的实例对象,该引⽤变量发出的⽅法调⽤到底是哪个类中实现的⽅法,必须在由程序运⾏期间才能决定。

多态分为编译时多态和运行时多态。其中编辑时多态是静态的,主要是指方法的重载,它是根据参数列表的不同来区分不同的函数,通过编辑之后会变成两个不同的函数,在运行时谈不上多态。而运行时多态是动态的,它是通过动态绑定来实现的,也就是我们所说的多态性。

    在 Java 中有两种形式可以实现多态:继承(多个⼦类对同⼀⽅法的重写)和接⼝(实现接⼝并 覆盖接⼝中同⼀⽅法)

15.面向对象五大基本原则是什么 **

单一职责原则(Single-Resposibility Principle)

一个类,最好只做一件事,只有一个引起它的变化。单一职责原则可以看做是低耦合、高内聚在面向对象原则上的引申,将职责定义为引起变化的原因,以提高内聚性来减少引起变化的原因。

开放封闭原则(Open-Closed principle)

软件实体应该是可扩展的,而不可修改的。也就是,对扩展开放,对修改封闭的。

里氏替换原则 (Liskov-Substituion Principle)

子类必须能够替换其基类。这一思想体现为对继承机制的约束规范,只有子类能够替换基类时,才能保证系统在运行期内识别子类,这是保证继承复用的基础。在父类和子类的具体行为中,必须严格把握继承层次中的关系和特征,将基类替换为子类,程序的行为不会发生任何变化。同时,这一约束反过来则是不成立的,子类可以替换基类,但是基类不一定能替换子类。

依赖倒置原则(Dependecy-Inversion Principle)

依赖于抽象。具体而言就是高层模块不依赖于底层模块,二者都同依赖于抽象;抽象不依赖于具体,具体依赖于抽象。

接口隔离原则(Interface-Segregation Principle)

使用多个小的专门的接口,而不要使用一个大的总接口。

16.**面向对象和面向过程的区别 ****

**
**

面向过程

优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源。

缺点:没有面向对象易维护、易复用、易扩展

面向对象

优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护

缺点:性能比面向过程低

17.String StringBuffer 和 StringBuilder 的区别是什么? String 为什么是不可变的? ***

**
**

可变性:

String 类中使⽤ final 关键字修饰字符数组来保存字符串, private final char value[] ,所以 String 对象是不可变的.

⽽ StringBuilder 与 StringBuffer 都继承⾃ AbstractStringBuilder 类,在 AbstractStringBuilder 中 也是使⽤字符数组保存字符串 char[]value 但是没有⽤ final 关键字修饰,所以这两种对象都是可变的。

安全性:

StringBuffer 对⽅法加了同步锁或者对调⽤的⽅法加了同 步锁,所以是线程安全的。StringBuilder 并没有对⽅法进⾏加同步锁,所以是⾮线程安全的。

性能:

StringBuffer 每次都会对 StringBuffer 对象本身进⾏操作,⽽不是⽣成新的对象并改变对象引⽤。相同情况下使⽤ StringBuilder 相⽐使⽤ StringBuffer 仅能获得 10%~15% 左右的性能提升。

18.static关键字 ***

static关键字的主要用途就是方便在没有创建对象时调用方法和变量和优化程序性能

1.static变量(静态变量)

用static修饰的变量被称为静态变量,也被称为类变量,可以直接通过类名来访问它。静态变量被所有的对象共享,在内存中只有一个副本,仅当在类初次加载时会被初始化,而非静态变量在创建对象的时候被初始化,并且存在多个副本,各个对象拥有的副本互不影响。

2.static方法(静态方法)

static方法不依赖于任何对象就可以进行访问,在static方法中不能访问类的非静态成员变量和非静态成员方法,因为非静态成员方法/变量都是必须依赖具体的对象才能够被调用,但是在非静态成员方法中是可以访问静态成员方法/变量的。

3.static代码块(静态代码块)

静态代码块的主要用途是可以用来优化程序的性能,因为它只会在类加载时加载一次,很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行。如果程序中有多个static块,在类初次被加载的时候,会按照static块的顺序来执行每个static块。

4**.初始化顺序**

静态变量和静态语句块优先于实例变量和普通语句块,静态变量和静态语句块的初始化顺序取决于它们在代码中的顺序。如果存在继承关系的话,初始化顺序为父类中的静态变量和静态代码块——子类中的静态变量和静态代码块——父类中的实例变量和普通代码块——父类的构造函数——子类的实例变量和普通代码块——子类的构造函数

5.静态变量和实例变量区别

静态变量:静态变量由于不属于任何实例对象,属于类的,所以在内存中只会有一份,在类的加载过程中,JVM只为静态变量分配一次内存空间。

实例变量:每次创建对象,都会为每个对象分配成员变量内存空间,实例变量是属于实例对象的,在内存中,创建几次对象,就有几份成员变量。

6.静态变量与普通变量区别

static变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。

7.静态方法和实例方法有何不同?

静态方法和实例方法的区别主要体现在两个方面:

在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方式。而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象。

静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法;实例方法则无此限制

19.**this关键字** **

1.this关键字可用来引用当前类的实例变量。

2.this关键字可用于调用当前类方法。

3.this()可以用来调用当前类的构造函数。

20.super关键字 **

1.super可以用来引用直接父类的实例变量。和this类似,主要用于区分父类和子类中相同的字段

2.super可以用来调用直接父类构造函数。(注意:super()一定要放在构造函数的第一行,否则编译不通过)

3.super可以用来调用直接父类方法。

21. 抽象类和接口区别:

**
**

** 普通类和抽象类有哪些区别?**

普通类不能包含抽象方法,抽象类可以包含抽象方法。

抽象类不能直接实例化,普通类可以直接实例化。

抽象类能使用 final 修饰吗?

不能,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承,这样彼此就会产生矛盾,所以 final 不能修饰抽象类

22. 成员变量与局部变量的区别有哪些? *

**
**

  1. 从语法形式上看:成员变量是属于类的,⽽局部变量是在⽅法中定义的变量或是⽅法的参数;成员变量可以被 public , private , static 等修饰符所修饰,⽽局部变量不能被访问控制修饰 符及 static 所修饰;但是,成员变量和局部变量都能被 final 所修饰。

2. 从变量在内存中的存储⽅式来看:如果成员变量是使⽤ static 修饰的,那么这个成员变量是属 于类的,如果没有使⽤ static 修饰,这个成员变量是属于实例的。对象存于堆内存,如果局 部变量类型为基本数据类型,那么存储在栈内存,如果为引⽤数据类型,那存放的是指向堆 内存对象的引⽤或者是指向常量池中的地址。

3. 从变量在内存中的⽣存时间上看:成员变量是对象的⼀部分,它随着对象的创建⽽存在,⽽局 部变量随着⽅法的调⽤⽽⾃动消失。

4. 成员变量如果没有被赋初值:则会⾃动以类型的默认值⽽赋值(⼀种情况例外:被 final 修饰 的成员变量也必须显式地赋值),⽽局部变量则不会⾃动赋值

23.内部类 **

内部类包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类

成员内部类

  1. 成员内部类定义为位于另一个类的内部,成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。

2.当成员内部类拥有和外部类同名的成员变量或者方法时,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问:外部类.this.成员变量

3.在外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问。

4.成员内部类是依附外部类而存在的,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象。

局部内部类

定义在方法中的内部类,就是局部内部类。

定义在实例方法中的局部类可以访问外部类的所有变量和方法,定义在静态方法中的局部类只能访问外部类的静态变量和方法。局部内部类的创建方式,在对应方法内,new 内部类()

匿名内部类

匿名内部类就是没有名字的内部类,日常开发中使用的比较多。

· 匿名内部类必须继承一个抽象类或者实现一个接口。

· 匿名内部类不能定义任何静态成员和静态方法。

· 当所在的方法的形参需要被匿名内部类使用时,必须声明为 final。

· 匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。

24.break ,continue ,return 的区别及作用**

break 跳出总上一层循环,不再执行循环(结束当前的循环体)

continue 跳出本次循环,继续执行下次循环(结束正在执行的循环 进入下一个循环条件)

return 程序返回,不再执行下面的代码(结束当前的方法 直接返回)

25.java 中 IO 流分为几种?*

按照流的流向分,可以分为输入流和输出流;

按照操作单元划分,可以划分为字节流和字符流;按照流的角色划分为节点流和处理流。

Java Io流共涉及40多个类,这些类看上去很杂乱,但实际上很有规则,而且彼此之间存在非常紧密的联系, Java I0流的40多个类都是从如下4个抽象类基类中派生出来的。

InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。

OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。

26.BIO,NIO,AIO 有什么区别?***

BIO (Blocking I/O):服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,可以通过线程池机制来改善。BIO方式适用于连接数目比较小且固定的架构

NIO (New I/O):服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有IO请求时才启动一个线程进行处理。NIO方式适用于连接数目多且连接比较短(轻操作)的架构

AIO (Asynchronous I/O):服务器实现模式为一个有效请求一个线程,客户端的IO请求都是由操作系统先完成了再通知服务器用其启动线程进行处理。AIO方式适用于连接数目多且连接比较长(重操作)的架构.

27.反射**

(1)什么是反射机制?

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

静态编译和动态编译

静态编译:在编译时确定类型,绑定对象

动态编译:运行时确定类型,绑定对象

(2)反射机制优缺点

优点:运行期类型的判断,动态加载类,提高代码灵活度。

缺点:性能瓶颈:反射相当于一系列解释操作,通知 JVM 要做的事情,性能比直接的java代码要慢很多。

(3)反射机制的应用场景有哪些?

在我们平时的项目开发过程中,基本上很少会直接使用到反射机制,但这不能说明反射机制没有用,实际上有很多设计、开发都与反射机制有关,例如模块化的开发,通过反射去调用对应的字节码;动态代理设计模式也采用了反射机制,还有我们日常使用的 Spring/Hibernate 等框架也大量使用到了反射机制。

举例:①我们在使用JDBC连接数据库时使用Class.forName()通过反射加载数据库的驱动程序;②Spring框架也用到很多反射机制,最经典的就是xml的配置模式。Spring 通过 XML 配置模式装载 Bean 的过程:1) 将程序内所有 XML 或 Properties 配置文件加载入内存中; 2)Java类里面解析xml或properties里面的内容,得到对应实体类的字节码字符串以及相关的属性信息; 3)使用反射机制,根据这个字符串获得某个类的Class实例; 4)动态配置实例的属性

28. 一些笔试题:

  • switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String 上

在 Java 5 以前,switch(expr)中,expr 只能是 byte、short、char、int。从 Java5 开始,Java 中引入了枚举类型,expr 也可以是 enum 类型,从 Java 7 开始,expr 还可以是字符串(String),但是长整型(long)在目前所有的版本中都是不可以的。

用最有效率的方法计算 2 乘以 8

  • 2

  • Math.round(11.5) 等于多少?Math.round(-11.5)等于多少

  • Math.round(11.5)的返回值是 12,Math.round(-11.5)的返回值是-11。四舍五入的原理是在参数上加 0.5 然后进行下取整。

  • float f=3.4;是否正确

不正确。3.4 是双精度数,将双精度型(double)赋值给浮点型(float)属于下转型(down-casting,也称为窄化)会造成精度损失,因此需要强制类型转换float f =(float)3.4; 或者写成 float f =3.4F;。

  • short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗

对于 short s1 = 1; s1 = s1 + 1;由于 1 是 int 类型,因此 s1+1 运算结果也是 int型,需要强制转换类型才能赋值给 short 型。

而 short s1 = 1; s1 += 1;可以正确编译,因为 s1+= 1;相当于 s1 = (short(s1 + 1);其中有隐含的强制类型转换。

29.String相关

什么是字符串常量池?

字符串常量池位于堆内存中,专门用来存储字符串常量,可以提高内存的使用率,避免开辟多块空间存储相同的字符串,在创建字符串时 JVM 会首先检查字符串常量池,如果该字符串已经存在池中,则返回它的引用,如果不存在,则实例化一个字符串放到池中,并返回其引用。

String 是最基本的数据类型吗

不是。Java 中的基本数据类型只有 8 个 :byte、short、int、long、float、double、char、boolean;除了基本类型(primitive type),剩下的都是引用类型(referencetype),Java 5 以后引入的枚举类型也算是一种比较特殊的引用类型。

这是很基础的东西,但是很多初学者却容易忽视,Java 的 8 种基本数据类型中不包括 String,基本数据类型中用来描述文本数据的是 char,但是它只能表示单个字符,比如 ‘a’,‘好’ 之类的,如果要描述一段文本,就需要用多个 char 类型的变量,也就是一个 char 类型数组,比如“你好” 就是长度为2的数组 char[] chars = {‘你’,‘好’};

但是使用数组过于麻烦,所以就有了 String,String 底层就是一个 char 类型的数组,只是使用的时候开发者不需要直接操作底层数组,用更加简便的方式即可完成对字符串的使用。

String有哪些特性

不变性:String 是只读字符串,是一个典型的 immutable 对象,对它进行任何操作,其实都是创建一个新的对象,再把引用指向该对象。不变模式的主要作用在于当一个对象需要被多线程共享并频繁访问时,可以保证数据的一致性。

常量池优化:String 对象创建之后,会在字符串常量池中进行缓存,如果下次创建同样的对象时,会直接返回缓存的引用。

final:使用 final 来定义 String 类,表示 String 类不能被继承,提高了系统的安全性。

30.JAVA异常 ***

异常主要分为Error和Exception两种

  • Error:Error类以及他的子类的实例,代表了JVM本身的错误。错误不能被程序员通过代码处理。

  • EXception:Exception以及他的子类,代表程序运行时发送的各种不期望发生的事件。可以被Java异常处理机制使用,是异常处理的核心。

  • 非检查异常(unckecked exception):该类异常包括运行时异常(RuntimeException极其子类)和错误(Error)。编译器不会进行检查并且不要求必须处理的异常,也就说当程序中出现此类异常时,即使我们没有try-catch捕获它,也没有使用throws抛出该异常,编译也会正常通过。因为这样的异常发生的原因很可能是代码写的有问题。

  • 检查异常(checked exception):除了Error和 RuntimeException的其它异常。这是编译器要求必须处理的异常。这样的异常一般是由程序的运行环境导致的。因为程序可能被运行在各种未知的环境下,而程序员无法干预用户如何使用他编写的程序,所以必须处理这些异常。

总计一下try{}catch(){}finally{}的执行顺序。

  • 先执行try中的语句,包括return后面的表达式;

  • 有异常时,执行catch中的语句,包括return后面的表达式,无异常跳过catch语句;

  • 然后执行finally中的语句,如果finally里面有return语句,执行return语句,程序结束;

  • finally{}中没有return时,无异常执行try中的return,如果有异常时则执行catch中的return。前两步执行的return只是确定返回的值,程序并未结束,finally{}执行之后,最后将前两步确定的return的返回值返回。

31.JAVA泛型 ***

Java 泛型是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。

  • 泛型擦除(这是面试考察泛型时经常问到的问题)

    Java的泛型基本上都是在编译器这个层次上实现的,在生成的字节码中是不包含泛型中的类型信息的,使用泛型的时候加上类型参数,在编译器编译的时候会去掉,这个过程成为类型擦除。

  • 例子ArrayList和ArrayList的原始类型是相同,在编译成字节码文件后都会变成List,JVM看到的只有List,看不到泛型信息,这就是泛型的类型擦除。

32.深拷贝与浅拷贝 ***

  • 深拷贝:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容,两个引用指向两个对象,但对象内容相同。

  • 浅拷贝:对基本数据类型进行值传递,对引用数据类型复制一个引用指向原始引用的对象,就是复制的引用和原始引用指向同一个对象。

33.常见的Object方法 ***

  • Object clone():创建与该对象的类相同的新对象

  • boolean equals(Object):比较两对象是否相等

  • void finalize():当垃圾回收器确定不存在对该对象的更多引用时,对象垃圾回收器调用该方法

  • Class getClass():返回一个对象运行时的实例类

  • int hashCode():返回该对象的散列码值

  • void notify():唤醒等待在该对象的监视器上的一个线程

  • void notifyAll():唤醒等待在该对象的监视器上的全部线程

  • String toString():返回该对象的字符串表示

  • void wait():在其他线程调用此对象的 notify() 方法或 notifyAll()方法前,导致当前线程等待

#Java开发##Java##学习路径#
全部评论

相关推荐

15 120 评论
分享
牛客网
牛客企业服务