面试-Java基础

文章目录

java介绍

解释下什么是面向对象?面向对象和面向过程的区别?

面向对象是一种“万物皆对象”的编程思想。以对象为中心,以消息为驱动。
它是一种更优秀的程序设计方法,基本思想是使用类、对象、继承、封装、消息等基本概念进行程序设计。
任何事物都可以抽象成一个对象来对待,之后再对这个对象进行相关操作。

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

  • 处理问题的角度不同:
    面向对象 = 注重事情有哪些参与者,及各自需要做什么
    面向过程 = 注重事情的每个步骤以及顺序
  • 编程思路不同:
    面向对象 = 抽象出类、属性、方法 =》 实例化类、执行方法
    面向过程 = 以实现功能的函数开发为主
  • 封装性:
    都具有封装性
    面向对象 = 封装的是数据和功能。
    面向过程 = 封装的是功能。
  • 具有属性不同:
    面向对象 有 继承性、多态性
    面向过程 没有 继承性、多态性

扩展:
OOP = object Oriented Programming 面向对象的编程,
OOD = object Oriented Design 面向对象的设计,
OOA = object Oriented Analysis 面向对象的分析

JDK、JRE、JVM三者之间的关系?

JDK = java development kit ,java程序开发工具,包括JRE、java工具、java基础库
JRE = java runntime environment,java运行时环境,包括JVM和核心类库
JVM = java virtual machine,java虚拟机,是java实现跨平台的核心
所有的java程序会首先被编译为.class的类文件,这种类文件可以在JVM上运行。

java中有没有goto?

有,goto是关键字,但是是保留字,不具备功能性。
扩展
这样询问的原因是:看java中是否保留了c语言中的goto语句的功能。
C语言中的goto语句允许无条件转移到同一函数内的被标记的语句。
语法:

goto label;

label:

基础语法

静态变量和实例变量的区别?
区别静态变量实例变量
语法定义被static关键字修饰没有
内存分配属于类而不属于具体对象,加载类会分配内存空间,且只分配一次;存储在JVM的方法区中属于某个对象,必须创建了具体对象,才会被分配内存空间;跟随对象存储在堆中
共享性被所有对象所共有,其中一个改变其值,其他对象访问则是改变后的值被对象所私有,某个对象改变其值后,不影响其他对象
调用形式类名.变量名对象名.变量名

共享性测试:

// 类
public class Demo {
    static int a = 1;//静态变量
    public int j = 1; // 实例变量
    // 构造方法,
    public Demo() {
        a++;
        j++;
        System.out.println(a + ", " + j);
    }

    // 输出结果是 2, 2
    //             3, 2
// 前者是静态变量,对象1 做了+1操作 对象2 又进行了+1操作 由于共享变量,所以a的值最终变成3
    // 后者是实例变量,属于每个不同的对象,所以都是从1 开始做+1操作,最终输出都是2
}
// 测试类
public class DemoTest {
    public static void main(String[] args) {
        Demo t1 = new Demo();
        Demo t2 = new Demo();
    }

}
Integer和int的区别?
区别Integerint
概念int的包装类基本数据类型
使用必须实例化后才能使用可以直接使用
本质是对象的引用,new Integer()产生一个指针指向此对象
对象存储在堆内存
直接存储数据 ,数据存储在栈内存
默认值null0

扩展分析:
非new生成Integer对象的形式是: Integer 变量名 = 变量值;

  • 由于Integer变量本质是对Integer对象的引用,所以通过new Integer创建的变量不可能相等,因为不同的对象存储地址不同;
  • Integer变量和int类型变量进行比较,只要两者值是相等的,结果就是true。因为包装类integer和基本类型int比较,java会默认执行拆箱操作,将Integer变量 变成 int类型变量,然后进行比较;
  • 非new生成的Integer对象 Integer i = 100 和 new Integer()生成的变量进行比较,结果为false。
    ① 变量值 在-128~127之间时 Integer 变量名 = 具体值 生成的变量指向的是java常量池中的对象;而new Integer()生成的变量指向的是堆中新建的对象;两者的内存地址不同;
    ② 变量值不在-128~127之间时 Integer i = 200 这种形式创建对象时,java API中最终会按照new Integer()形式创建对象,所以两者的内存地址还是不同;
  • 两个非new生成Integer对象,值相同进行比较。两个变量的值在-128~127之间,结果为true;反之,结果为false;
    ①两个变量的值在-128~127之间,说明两者同时执行java常量池中的对象,内存地址相同,结果为true;
    ②两个变量的值不在-128~127之间,说明变量最终会通过new Integer()创建,产生两个不同的对象,内存地址不同,结果为false;
装箱和拆箱的区别

每一种基本数据类型,都有其相对应的包装类。byte–Byte,char–Character,short–Short,int–Integer,long–Long,float–Float,double–Double。
以Integer 对象 ii 和 int 变量 i 为例

区别装箱拆箱
概念将基本数据类型封装成对应的包装类将包装类 转换成 对应的基本数类型
手动实现Integer ii = Integer.valueof( 100 )int i = ii.intValue()
自动实现Integer ii= 100ii += 200
包含自动拆箱 ii + 200,自动装箱 ii = ii + 200的赋值过程
final、finally、finalize的区别?
对比项说明
final修饰属性-表示属性不可变(常量)
方法-表示不可覆盖(重写)
类-不可继承
finally异常处理语句的一部分,表示总是执行
常用于异常处理时的所有清除操作,比如IO流中的释放资源操作
finalizeObject类的一个方法,在垃圾回收时会调用被回收对象的finalize
java中的Math.round(-1.5)等于多少?

Math.round(-1.5)结果是-1,因为在数轴上,中间值0.5是向右取整,都会向大的方向走,那么正数会向上取整,负数则会直接舍去(也是向大的方向取整);
比如 Math.round(-1.5) => -1 ,Math.round(-1.2) => -1,Math.round(-1.8) => -2

两个二进制数的异或结果是什么?

两个二进制数的异或结果是 两个二进制数差的绝对值,表达式:a^b = |a - b|
案例:如果a = 1001 b= 1011 ,则a^b=0010 = 2(十进制) |a-b| = |9-11| = 2

static关键字的作用?

具体作用:

具体作用说明
静态变量
类变量
变量属于类,类的所有实例都共享静态变量,可以通过类名直接访问
静态变量在内存中只存在一份
静态方法类加载的时候就存在,不依赖与任何实例
静态方法必须实现,不能是抽象方法
只能访问所属类的静态属性和静态方法,方法中不能有this和super关键字
静态语句块在类初始化时运行一次
静态内部类不能访问外部类的非静态的变量和方法
非静态内部类依赖于外部类的实例,静态内部类不需要

具体静态xxx

// idea_face-test2-StaticDemo
public class StaticDemo {
    public static String staticFieldString = "静态变量";
    static{
        System.out.println("静态语句块");
    }
    public String field = "实例变量";
    {
        System.out.println("普通语句块");
    }
    public StaticDemo(){
        System.out.println("构造方法");
    }
}

初始化顺序:

  • 普通类:
    静态变量和静态语句块 优先于 实例变量和普通语句块,而静态变量和静态语句块的初始化顺序取决于他们代码中的顺序。
  • 存在继承的初始化顺序:父类、子类都存在静态变量、静态语句块、实例变量、普通语句块、构造方法
    ①父类(静态变量,静态语句块)②子类(静态变量,静态语句块)③父类(实例变量、普通语句块)④父类(构造方法)⑤子类(实例变量、普通语句块)⑥子类(构造方法)
super关键字的作用?
  • 访问父类的构造方法:super()
    使用super()方式访问父类的构造方法;
  • 访问父类的成员方法:super.成员方法()
    如果子类重写了父类的某个方法,可以通过使用super关键字来引用父类的方法实现;
  • 访问父类的成员变量:super.成员变量名

扩展:
【this和super不能同时出现在一个构造方法中,因为同时调用父类的构造器会造成初始化父类的两次不安全操作】
理解如下:
准确来说是 this调用本类构造器,super调用父类构造器时,不能同时出现。同时存在会造成初始化父类的两次不安全操作。
也就是 this调用本类属性或方法 super调用父类属性或方法 的时候,可以同时出现。

java规定,在执行构造方法之前,必须执行父类的构造方法,直到这个类是java.lang.Object类的构造方法

  • 子类的构造方法第一句都会执行父类的构造方法。如果没有添加super关键字,系统会默认添加super()语句;如果有super关键字显示的调用父类构造方法,那么就会使用指定的父类构造方法,否则使用无参构造方法。
  • 假如构造方法中存在this()和super()。this会调用本类其他的构造方法,按照递归,最终还是会调用父类的构造方法,那么两者同时存在,就会造成初始化父类的两次不安全操作。
字节和字符的区别?

字节是存储容量的基本单位。
字符是数字、字母、汉字以及其他语言的各种字符。
1 字节 = 8个二进制单位,一个字符由一个字节或多个字节的二进制单位组成。

char型变量中能不能存贮一个中文汉字?为什么?

char型变量可以存储一个中文汉字。
char是16位,占两个字节。汉字通常使用GBK或者UNICODE编码,也是占两个字节。
其中UTF-8占三个字节。

数组为null和长度为0的区别
语句说明运行问题
int [] n ;只声明了一个数组变量变量没有初始化,打印输出“可能尚未初始化变量n”
int[] nil = null ;声明一个数组变量,并赋值为null,nil是一个数组类型的空引用,不指向任何对象虽已初始化,打印“nil.length” 会出现异常:NullPointException
int[] zero = new int[0];声明并创建一个数组对象,长度是0,只是包含元素个数为0打印zero.length 是0,数组内没有元素
权限访问介绍?

有三种权限修饰符:public、private、protected。修饰目标的时候会有四种访问权限;

修饰成员:
private——该类的成员访问;
default——同一包下的其他类 + 该类的成员访问;
protected——该类的子类 + 同一包下的其他类 + 该类的成员访问;
public——任意包下的任意类的成员访问;

修饰类:
default——同一包的其他类访问;
public——任意包下的任意类访问。

运算符

short s1 =1;s1 = s1 + 1; 有什么错? 那么 short s1 = 1;s1 += 1; 有没有错?

short s1 =1;s1 = s1 + 1;
有错,错误的根本原因是算术运算符+号底层没有包含强制类型转换。s1 = s1 + 1;的计算会将s1的类型自动提升为int类型,那么计算过程就为short = int + int,此时会报不兼容类型的错误:从int类型到short类型会有数据损失。

short s1 = 1;s1 += 1;
没有错,因为扩展的赋值运算符底层包含了强制类型转换。s1 += 1;计算过程中,会将等号右侧int类型转换为short类型。

& 和 && 的区别?

逻辑& 短路逻辑&&
当两侧的表达式都是true的时候,整个运算结果才是true,否则是false。
两者的区别是:
短路逻辑&& 只要左侧表达式是false,则右侧表达式就不会计算了。
逻辑& 左侧表达式无论结果是true还是false,右侧表达式都会计算。
还可以进行按位运算,两边不是boolean类型时,表示按位运算。

== 和equals的区别?

==

  • 基本数据类型:数值是否相等
  • 引用数据类型:比较对象的地址是否相等

equals

  • 对象内容:比较对象内容是否相等(因为其重写了)
  • 不能比较基本数据类型的变量是否相等;
  • equals方法没有重写,比较的是引用类型的变量所指向的对象的地址
  • equals大部分情况下被重写,比如String、Integer等把它变成了值比较,所以一般情况下equals比较的是值是否相等

流程控制

switch语句能否作用在byte上,能否作用在long上,能否作用在String上?

switch语句能作用在byte上,jdk7之后可以作用于String,不能作用于long。
switch语句的表达式只能是整数表达式或枚举类型,整数表达式主要是int基本数据类型或Integer包装类。
switch语句不仅能作用于btye,而且还有char、short 类型,因为它们都可以隐式转化为int类型。

扩展
jdk1.7之后,switch可以作用在String上,本质上是 编译时将字符串 替换为 对应的hash值。

面向对象

& 重载和重写的区别?

概念不同,重载是编译时多态,重写是运行时多态;
重载更多的体现是在类的构造方法,不同的构造方法的区别在于参数不同,而参数不同体现在参数类型以及个数不同;
重写主要体现在子类继承父类,需要重写父类的方法;重写的目的:在于父类引用可以根据子类对象运行时实际类型的不同而调用不同的实现代码。

java是否可以重写一个private或static方法?

java不能重写一个private方法。
因为private修饰的变量或方法只能在当前类中使用,如果是其他的类继承了当前类是不能访问到private修饰的变量或方法的,更不能重写。
java不能重写一个static方法。
static方法可以被继承,但是不能被重写。方法重写(覆盖)是基于运行时动态绑定的,而static方法是编译器一开始就确定的静态绑定。

java中实现多态的机制是什么?

类的多态的条件:
①父类(接口)引用指向 子类(实现类)对象
②方法有重写

具体的实现是:

父类 对象名 = new 子类();
接口 对象名 = new 实现类();
java中创建对象的几种方式?

java创建对象有四种方式:new、反射使用newInstrance、clone、反序列化创建对象
new
具体的实现是:

类名 对象名 = new 类名();
多态的形式
父类名 对象名 = new 子类名();
接口名 对象名 = new 接口实现类名();

newInstrance

  • 获得Class对象 有三种方式 Class类的静态方法forName、Class类的class属性、对象的getClass方法
1 通过Class类的静态方法 forName()获得 类的字节码文件对象
	Class<?> c = Class.forName("类的路径");
2 通过对象的getClass方法获得Class类对象
	Class<?> c = 对象.getClass();
3 通过类的class属性 获得Class类对象
	Class<?> c = 类名.class;
  • 利用Class对象的getConstructor()方法获得指定的构造器
constructor<?> con = c.getConstructor();
  • 调用Constructor的newInstance()方法创建java对象
Object obj = con.newInstance();

反序列化创建对象
使用反序列化创建对象,首先要使用序列化创建对象,并实现对象的序列化。

  • 序列化创建对象ObjectOutputStream
1 创建序列化对象
objectOutputStream oos = new objectOutputStream(new FileOutputStream("文件路径"));
2 创建对象
类名 obj = new 类名();
3 写入序列化流对象
oos.writeObject(obj);
4 释放资源
oos.close();
  • 反序列化创建对象 ObjectInputStream
1 创建反序列化对象
objectInputStream ois = new objectInputStream(new FilInputStream("文件路径"));
2 使用方法readObject()读取对象
Object obj = ois.readObject();
3 释放资源
ois.close();

clone()
使用的是java.lang.Object类中的方法clone(),由于java中所有的类都默认继承java.lang.Object类,所有类创建的对象都可以调用clone方法。

1 通过类创建对象
类名 对象名1 = new 类名();
2 使用clone()创建对象
类名 对象名2 = (类名)对象名1.clone();
一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制?

可以包含多个类,但是只能有一个public修饰的类,可以出现多个非public修饰的类。
其中public类的类名必须与.java的文件名一致。

方法

& 构造方法有哪些特性?
  • 构造方法名 和 类名 必须保持一致
  • 构造方法无返回值类型(void 也不行)
  • 构造方法不能被static final abstract synchronized native等修饰符修饰,可以被public、private、protected修饰;
  • 构造方法不能被继承
  • 在执行的时候,无参构造方法会自动生成;如果类中定义了带参构造方法,则不会自动生成无参构造方法
  • 构造方法的调用是在创建一个对象时使用new操作符进行的,作用是初始化对象
  • 多个构造方法之间的关系是 方法重载

备注2022/8/14
不能被static修饰——构造器总是关联着一个对象而被调用;
不能被final修饰——构造器不能被继承,没有必要被final修饰;
不能被abstract修饰——一个抽象的构造器将永远不能被实现;
不能被native修饰——本地化的方法情况特别复杂,所以JVM调用起来很麻烦,没有native的情况下,JVM实现起来比较容易;

在Java中定义一个不做事且没有参数的构造方法有什么用?(无参构造方法)

Java中不做事且没有参数的构造方法 = 无参构造方法
1 【子类继承父类场景】Java程序在执行子类的构造方法之前,如果没有使用super()来调用父类指定的构造方法,则会调用父类中的无参构造方法
此时,父类中没有无参构造方法,则编译时会发生错误。
2 【初始化】无参构造方法 一般用来初始化:为变量赋值、初始化对象等。

Java中的参数传递是传值呢?还是传引用?

Java中的参数传递是以值传递的形式传入方法。
传递的是基本数据类型(数字及布尔值):一个方法不可能修改一个基本数据类型参数的值
传递的是引用数据类型:一个方法可以修改一个引用数据类型参数所指向对象的值

abstract的method 是否可是static,是否可以是native,是否可以是synchronized?
修饰符修饰符解释是否与abstract可以同时出现解释
abstract抽象方法(abstract的method)是指该方法只有声明而没有实现,它的实现要放入声明该类的子类中实现
static静态方法(static的method)只属于当前类abstract 说明需要子类重写方法,static 说明可以使用类名直接调用 ,两者同时出现表示通过类名调用抽象方法,这样肯定不行。
native本地方法,只有方法声明没有方法实现,它将具体实现移交给了本地系统的函数库,没有通过虚拟机,可以说是java与其他语言通讯的一种机制。abstract 和 native 本身就冲突,他们都是方法申明,一个是将方法实现移交给子类,另一个是将方法实现移交给本地操作系统,同时出现会造成矛盾,不知道该将方法实现移交给谁
synchronized是同步,是针对线程的锁,需要有具体操作才能同步。方法上使用synchronized,将会使用该方法的调用者作为同步监视器(this)。abstract只有方法申明,没有具体实现,那么添加synchronized,同步一些什么东西将会产生一个问题
构造器Constructor是否可被override?是否可以继承String类?

构造器Constructor不能被重写(override)
子类不能继承父类的构造方法,所以就不存在重写父类的构造方法。
super() 表示子类调用父类的构造方法,不叫做继承父类的构造方法。

构造器Constructor不能继承String类
String是final修饰的,也就是最终类、子类,所以不能被继承。

& 静态方法不能去调用非静态变量和方法,为什么调用是非法的?

非静态变量和方法是属于类的实例对象的,这些只有在类实例化时创建的,之后实例访问;
静态方法属于类,在类加载的时候就会创建;
一个静态方法访问非静态变量或方法的时候,非静态成员可能还没有分配内存,也就是还不存在的情况,此时访问就是非法的。

& 子类的构造方法中如何使用父类的构造方法?

子类的构造方法通过super方法去使用父类的构造方法。
如果父类中没有写有参构造方法,会有默认的无参构造方法;如果有有参构造方法,那么就没有无参构造方法了,需要自己定义;
如果是有无参构造方法,则会自动调用;如果需要调用有参构造方法,通过super方法加参数即可。

接口和类

抽象类和接口有什么区别?
区别抽象类接口
成员变量可以是变量、常量,
修饰符可以是pubilc、默认、protected
只能是常量 且修饰符是public static final
成员方法抽象方法 public abstract 修饰抽象方法 public abstract
具体方法 修饰符可以是public、默认、protected默认修饰符只能是default
可以有静态方法JDK8可以有静态方法,必须实现且只能使用public修饰或省略不写
构造方法可以定义构造方法不可以定义构造方法
设计理念对类的行为、属性 进行抽象对类的行为 进行抽象
继承/实现可以继承一个类
实现多个接口
可以继承一个或多个接口
添加新的方法给抽象类添加新方法,提供默认实现,就不需要改现有代码接口中添加新方法,必须修改该接口的实现类

理解分析:

  • JDK1.8之前接口中不允许出现静态方法,因为接口不可以实现方法,只可以定义方法,而静态方法需要被实现,所以接口不能含有静态方法。实现 的含义是 方法有方法体,且有具体的内容。

抽象类和接口区别的代码实现

package com.javaface5.test523.test2;

public abstract class testAbstractInterface {
    // 成员属性
    public int a; // public修饰
    int b; // 默认形式
    protected int c; // protected修饰

    // 抽象方法
    public abstract void method();
    // 具体方法
    public void method1(){
        System.out.println("具体的方法 public修饰");
    }
    void method2(){
        System.out.println("具体的方法 默认修饰符");
    }
    protected void method3(){
        System.out.println("具体的方法 protected修饰");
    }

    // 静态方法
    public static void method4(){
        System.out.println("静态方法 static修饰");
    }

    // 带参构造方法。
    public testAbstractInterface(int c){
        this.c = c;
    }
}
package com.javaface5.test523.test2;

public interface testInterface {
    // 成员变量只能是 public static final 常量
    public static final int intValue = 10;

    // 抽象方法
    public abstract void method();

    // 具体方法 修饰符只能是default
    default void method2(){
        System.out.println("具体方法 修饰符只能是default");
    }

    // 静态方法
    public static void method3(){
        System.out.println("静态方法 修饰符static");
    }

    // 构造方法 会报错
//    public testInterface(){
//
//    }
}
抽象类、接口、实体类之间的继承、实现关系
接口抽象类实体类
接口继承接口(单继承、多继承)
抽象类抽象类不可以继承接口
抽象类可以实现接口
抽象类可以继承抽象类
抽象类A继承了抽象类B,那么抽象类A可以不覆盖B中的抽象方法
抽象类可以继承实体类,取决于实体类是否有明确的构造函数
所有抽象类都继承自Object类
实体类实体类可以实现多个接口
实体类可以继承抽象类实体类可以继承实体类

Java抽象类继承抽象类

// 抽象类A 
abstract class A{
	abstract void add(); // 抽象方法
	public void delete(){}; // 普通方法
}

// 继承自抽象类A的抽象类B
abstract class B extends A{
	// 由于抽象类B继承了抽象了A,在抽象类B中可以不重写抽象类A的抽象方法;
	// abstract void add();
	abstract void getXX();
}

// 普通类继承抽象类B,抽象类B又继承抽象类A
public class C extends B{
	// 必须实现抽象方法,且需要实现抽象类A和抽象类B的抽象方法
	public void add(){}
	public void getXX(){}
	
}

备注2022/8/14
抽象类A、B,且其中的抽象方法分别是a、b,则普通类C继承抽象类A、B,必须重写方法a、b。

接口是否可以继承接口?抽象类是否可实现接口?抽象类是否可以继承实体类(concrete class)?
问题解答案例
接口是否可以继承接口一个接口可以继承一个或多个接口List接口继承自Collection接口
抽象类是否可以实现接口抽象类可以实现一个或多个接口MouseAdapter鼠标监听适配器 – 抽象类,实现了 MouseListener 接口
抽象类是否可以继承实体类抽象类可以继承一个类所有抽象类都继承自Object类
内部类可以引用外部类的成员吗?有没有什么限制?

可以使用。
如果非静态内部类,可以使用外部类的所有成员;
如果是静态内部类,只能使用外部类的静态成员。

Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可以 implements(实现)interface(接口)?

匿名内部类本质上就是 在继承其他类,实现其他接口。

    public static void main(String[] args) {
        // 创建线程 Thread是一个类
        new Thread(){
            @Override
            public void run() {
                super.run();
            }
        };
        // 创建线程 Runnable是一个接口
        new Runnable() {
            @Override
            public void run() {
                
            }
        };
    }
}
继承一定要重写父类的方法吗?

普通类继承:不一定重写父类的方法;
抽象类继承:①如果子类是抽象类,则不用重写父类的方法;②如果子类不是抽象类,则一定要实现父类的抽象方法;
接口继承:①子接口,可以扩展父接口的方法;②子抽象类,可以部分或全部实现父接口的方法;③普通类,则子类必须全部实现父接口的全部方法;

集合

两个对象的hashCode()相同,则equals()也一定为true吗?

两个对象的hashCode()相同,equals()不一定为true。因为在哈希表中,hashCode()相等表示两个键值对的哈希值相等,然而哈希值相等,不一定能得出键值对相等(散列冲突)。
散列冲突 表示: 在key1!=key2的时候,经过哈希函数处理,hash(key1) = hash(key2).原因是:再好的哈希函数,由于哈希值是非负的,总量是有限的,而在现实中所需要处理的键是无限的,将无限的集合映射到有限的的集合中,肯定避免不了冲突。

散列表 = HashTable,哈希表。散列函数 = 哈希函数。
基本原理:通过哈希函数 将元素的键映射为数组下标(散列值或哈希值)

为什么重写equals()就一定得重写hashCode()方法?

前提 如果没有用到HashMap、HashSet等集合,即用不到哈希表的时候,仅重写equals()也是可以的;
但是一般情况下,实际场景中会用到哈希表的,所以java官方建议重写equals()就一定重写HashCode()。

原因
重写equals方法同时重写hashCode方法,这样做是为了保证两个方法的一致性,也就是equals方法返回true,则两个对象的hashcode也相同。

实际情况分析
进行集合对象的判重,如果一个集合中有10,000个对象,仅使用equals()方法,对于一个对象的判重就需要进行10,000次比较,随着集合规模的增大,时间开销很大。同时使用哈希表的话,能快速定位到对象的大概存储位置,后续比较中,如果对象的hashCode()不同,则就不用调用equals()方法,减少了equals()的比较次数。

扩展:hashCode() 和 equals()的相关性

  • 两个对象相等,则hashCode值一定相等
  • 两个对象相等,对两个对象分别调用equals方法都返回true
  • 两个对象有相同的hashCode值,两个对象不一定相等
  • equals方法被覆盖过,则hashCode方法也必须被覆盖
  • hashCode方法默认的行为是对堆上的对象产生独特值,如果没有重写hashCode方法,则该class类的两个对象无论如何都不会相等(即使两个对象指向相同的数据)

hashCode方法的默认行为
hashCode方法的默认返回值被称为identity hash code,即使重写了hashCode方法,还可以调用System.identityHashCode(o)得到对象的identity hash code。
identity hash code 使用了内存地址的整数表示,但这个实现不是必需的。大致意思就是说hashCode计算通常和对象的内存地址有关,但具体的实现由jvm决定,jvm不同,实现就可能不同。
hashCode方法的实现依赖于jvm,不同的jvm有不同的实现。

两个对象值相同(x.equals(y) == true),却可有不同的hash code,这句话对不对?

这句话是不对的。两个对象值相同,hash code一定相同;但hash code 相同,两个对象的值不一定相同。
由于Object类中的equals()方法重写的同时,要求hashCode方法也一起重写,这样的目的是保证两个方法的一致性,即当equals返回true时,两个对象具有相同的hash值。

序列化

什么是java的序列化,如果实现java的序列化?

对象的序列化 = 将对象状态转化为字节流。
反序列化 = 从字节流转化为对象。

实现序列化:

1 被序列化的类实现Serializable接口
	pubilc class 类名 implements Serializable{}
2 创建对象序列化流对象
	ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("文件路径"));
3 创建类的对象
	类名 obj = new 类名();
4 使用write方法将对象写入序列化流对象中
	oos.writeObject(obj);
5 释放资源
	oos.close();
什么情况下需要序列化?
  • 想把对象状态保存到一个文件或数据库中的时候
  • 想使用套接字在网络上传输对象的时候
  • 想通过RMI传输对象的时候

扩展:
套接字 = Socket,可以看成网络中不同主机上的应用进程之间进行双向通信的端点的抽象。
RMI(Remote Method Invocation),远程方法调用,是运行在一个Java虚拟机上的对象调用运行在另一个Java虚拟机上对象的方法。

transient关键字的作用?

对于不想进行序列化的变量,使用transient关键字修饰。
可以实现阻止实例中用transient关键字修饰的变量被序列化。当变量被反序列化时,被transient修饰的变量值不会被持久化和恢复。(不会被持久化 = 不能被序列化存储到文件中)

注意
transient只能修饰变量,不能修饰类和方法。
被static修饰的静态变量天然不能被序列化。
参考连接

泛型

& Java的泛型是如何工作的?什么是类型擦除?
  • 泛型概念:
    泛型的本质是类型参数化,等价于 所操作的数据类型被指定为一个参数;
    它是通过类型擦除将数据类型变成一个变量,编译器在编译时擦除了所有类型相关的信息,所以在运行时不存在任何类型相关的信息。
  • 类型擦除:
    泛型信息只存在于代码编译阶段,在进入JVM之前,与泛型相关的信息会被擦除掉,专业术语称之为类型擦除。
    在泛型类被类型擦除之前,泛型类中的类型参数如果没有指定上限,即< T >则会被直接转义为Object类型;
    如果指定了上限,即< T extends String >则类型参数会被直接替换成类型上限String。

扩展:

  • 案例:
List<String> list = new ArrayList<String>();
解释:
1 两个String只有第一起作用,但是省略后一个String的形式JDK7之后才允许。
2 第一个String,表示List存储的是String
什么是泛型中的限定通配符和非限定通配符?

限定通配符 对类型进行了限定。有两种类型:

  • < ? extends T > 表示?类型必须是T的子类 或者 T类型
  • < ? super T > 表示?类型必须是T的父类 或者 T类型

非限定通配符 没有对类型进行限定。

  • < ? > 表示用任何类型来替代
List< ? extends T > 和 List< ? super T> 之间有什么区别?

两个都是限定通配符。
List< ? extends T > 可以接受任何 继承自T类型(T类型的子类或者T类型) 的List
List< ? super T > 可以接受任何 T的父类 构成的List
扩展:
Array(数组)不支持泛型,要用List代替Array,因为List可以提供编译器的类型安全保证,而Array却不能。

进阶

java中的反射是什么意思?有哪些应用场景?
  • 概念:
    动态获取信息 以及 动态调用对象的方法 的功能称为反射机制;
    在运行状态中,对于一个类,能够知道类的所有属性和方法;对于一个对象,能够调用它的任意一个方法和属性。

  • 应用场景:
    模块化的开发(通过反射去调用对应的字节码)、动态代理、框架的设计(Spring、Hibernate)、工厂模式(使用反射机制根据全限定类名获得某个类的Class实例;应该就是Class.forName(“全限定类名”))。

反射的优缺点?
  • 优点:
    运行期类型的判断,动态加载类,提高代码灵活度

  • 缺点:
    性能瓶颈:反射相当于一系列解释操作,涉及动态类型的解析,JVM无法对代码进行优化,性能比直接的java代码要慢很多
    安全问题:可以动态操作改变类的属性同时也增加了类的安全隐患。反射技术要求程序必须在一个没有安全限制的环境中运行。
    内部暴露:反射操作允许执行一些正常情况下不被允许的操作(比如:访问私有方法或属性),可能会导致代码失调并破坏可移植性和抽象性,当平台发生改变,代码的行为可能会随之改变。

java中的动态代理是什么?有哪些应用?

动态代理
给实现了某个接口的类中的方法添加额外处理,给这个类创建代理,即创建一个新的类。新的类不仅具有原来类方法的功能,而且还添加了额外处理的新功能。
在程序运行时,运用反射机制动态创建而成,动态代理类的字节码在程序运行时由java反射机制动态生成,无需程序员手动编写它的源代码。
应用
Spring的AOP、加事务、加权限、加日志。

怎么实现动态代理?

具体步骤如下所示

  • 1 创建一个接口MyInter,并且声明抽象方法method1,method2
public interface MyInter{
	public abstract 返回值 method1();
	public abstract 返回值 method2();
}
  • 2 创建接口的真实实现类RealClass,并重写所有抽象方法
public class RealClass implements MyInter{
	@Override
	public 返回值类型 method1(){
		method1具体实现;
	}
	@Override
	public 返回值类型 method2(){
		method2具体实现;
	}
}
  • 3 创建接口的代理类,实现InvocationHandler
public class ProxyClass implements InvocationHandler{
	创建接口对象,通过真实类创建
	MyInter interObj = new RealClass();
	
	创建接口代理类的构造方法(带参)
	public ProxyClass(MyInter interObj){
		this.interObj = interObj;
	}
	
	重写Object类中的invoke方法
	@Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // proxy: 被代理的对象
        // method:调用的方法
        // args:方法所需要的参数
        System.out.println("before");
        Object result = null;
        try{
            // 利用反射动态的来反射方法,动态代理和静态代理的区别
            result = method.invoke(interObj, args);
        }catch(Exception e){
            System.out.println("ex:" + e.getMessage());
        }finally {
            System.out.println("after");
        }
        return result;
    }
}
  • 4 创建测试类
public class jdkTest{
	public static void main(String[] args){
		创建MyInter接口对象
		MyInter realinter = new RealClass();

		创建InvocationHandler接口对象
		InvocationHandler handler = new ProxyClass(realinter);

		调用Proxy.newProxyInstance()方法 创建指定接口的代理实例
		MyInter myinter = (MyInter)Proxy.newProxyInstance(jskTest.class.getClassLoader(),new Class[]{MyInter.class},handler);
		
		代理对象访问实际接口方法
		myinter.method1();
		myinter.method2();
		}
}
如何实现对象的克隆

实现克隆的方式有两种:
① 实现Cloneable接口并重写clone()方法;

1 被克隆对象所属类必须实现Cloneable接口
public class 类名 implements Cloneable{}
2 所属类必须重写Object类的clone方法
@Override
public Object clone() throws CloneNotSupportedException{
	类名 obj =(类名)super.clone(); // 浅克隆
	// 强制类型转换,把Object类转为 类名
	obj.属性名 = (属性类)属性名.clone(); //深克隆
	// 强制类型转换,把Object类转为 属性类
	return obj;
}

②实现Serializable接口,通过对象的序列化和反序列化实现克隆;

// 要序列化对象所属类 需要实现Serializable接口
public class 类名 implements Serializable{}
// 序列化
1 创建序列化流
	ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("文件路径"));
2 创建对象
	类名 obj = new 类名();
3 使用序列化流的writeObject方法将对象写入指定的ObjectOutputStream流中
	oos.writeObject(obj);
4 释放资源
	oos.close();
// 反序列化
1 创建反序列化流
	ObjectInputStream ois = new ObjectInputStream(new FileInputStream("文件路径"));
2 使用反序列化流的readObject方法从ObjectInputStream流中读取一个对象
	Object obj = ois.readObject();
3 强制转化对象类型
	类型 obj1 = (类型)obj;
4 释放资源
	ois.close();
深克隆和浅克隆的区别

两者的区别是:克隆的新对象和原始对象的引用类型属性(变量/常量)是否是同一个对象。
浅克隆:新对象和原始对象的引用类型属性是同一个对象,只是复制了对象的引用地址,两个对象指向同一个内存地址;
深克隆:新对象和原始对象的引用类型属性不是同一个对象,修改其中一个对象的引用类型属性,另一个不受影响。

String

String为什么设置为不可变类?

原因如下:

  • 字符串常量池的需要。
    字符串常量池是java堆内存的特殊存储区域。创建一个String对象的时候,假如字符串值已经存在于常量池中,则不会再创建一个新的对象,而是引用已经存在的对象。
  • 允许String对象缓冲HashCode。
    java中的String对象的哈希值被频繁地使用(比如:HashMap等容器中),字符串不变性保证了hash码的唯一性,因此可以放心地进行缓存。
  • String被许多java类(库)用来当做参数。
    比如:网络连接地址URL、文件路径path、反射机制所需要的String参数,如果String不是固定不变的,将会引起各种安全隐患。
String、StringBuilder、StringBuffer的区别?
类型说明
String字符串常量(线程安全)
StringBuilder字符串变量(线程不安全)
字符串缓冲区
StringBuffer字符串变量(线程安全)
对方法加了同步锁

使用区别:

  • String字符串内容不可变,修改String字符串的内容实际上是在堆内存中重新开辟内存存储新的字符串,并将内存地址赋值给String字符串变量;
  • StringBuilder字符串内容是可变的,修改字符串是修改字符串变量对应内存地址存储的字符串,不会造成内存空间的浪费;
  • 在修改字符串操作比较多的时候使用StringBuilder或StringBuffer,要求线程安全使用StringBuffer,不要求线程安全使用StringBuilder。
  • 三者的执行效率:StringBuilder > StringBuffer > String
String字符串修改实现的原理?

对String字符串进行修改的步骤是:

1 创建String类型字符串
	String s = "abcxxxx";
2 创建StringBuilder对象
	StringBuilder sb = new StringBuilder(s);
3 使用StringBuilder对象的append方法,实现字符串的添加
	sb.append("");
4 使用StringBuilder对象的toString方法,实现StringBuilder =String类型
	sb.toString();
String str = “i” 和 String str = new String(“i”)一样吗?

不一样。内存的分配方式不一样。String str = "i"方式,java虚拟机会将其分配到常量池中(常量池位于堆内存);String str = new String(“i”)方式,java虚拟机会将其分配到堆内存中。

  • String str = “i” ; String str2 = “i”
    表示把i在内存中的地址赋值给str变量,如果有String str2 = “i” ,由于i在常量池中已经存在,所以会将i在常量池中的地址赋值给str2。两个引用的是同一个地址,共享同一个内存空间。
  • String str3 = new String(“i”) ;String str4 = new String(“i”)
    表示将new String出来的新对象存储的地址赋值给str3,新对象存储在堆栈中。String str4 = new String(“i”)表示又创建一个新对象,并将对象的地址赋值给str4
String类的常用方法有哪些?
方法名说明
int indexOf()返回指定字符的索引
有四个方法
参数可以是:int ch ; int ch,int fromIndex;String str ; String str,int fromIndex
char charAt(int index)返回指定索引处的字符
String replace(String oldstr,String newstr)字符串替换
String trim()去除字符串两端空白
String[] split(String regex,int limit)分割字符串,返回一个分割后的字符串数组
byte[] getBytes()返回字符串的Byte类型数组
int length()返回值字符串的长度
String toLowerCase()将字符串转成小写字母
String toUpperCase()将字符串转成大写字母
String substring(int beginIndex,int end Index)截取字符串
Boolean equals(String str)字符串比较
final修饰StringBuffer后可以使用append方法吗?

可以使用append()方法。
因为final修饰一个引用类型,表示变量的引用地址不能改变,即所指向的对象不变,但是对象中的属性可以改变。通过append可以改变对象的属性值。

String s = new String(“xhj”); String s1 = “abc”; 创建了几个String Object

String s1 = “abc”;
会创建0个或1个对象。
直接赋值,字符串“abc”会被存储在字符串常量池中,只有一份;
如果字符串常量池中已经存在“abc”,那么不会再创建“abc”字符串,而是把地址赋值给变量s1

String s = new String(“xhj”);
会创建1个或2个变量。
“xhj” —— 本身就是一个字符串,会被存放在常量池中,创建1个变量;当字符串“xhj”存在于常量池中的时候,那么不会再创建字符串,此时就没有创建字符串对象。也就是这个字符串创建有两种可能性0或者1.
new String(“xhj”)——会创建一个字符串,存储在堆中,地址引用赋值给s,并存储在栈中。

String是最基本的数据类型吗?

不是。String是类类型。基本数据类型包括byte、short、char、int、long、float、double、Boolean类型。

IO流

java中的IO流的分类?说出几个你熟悉的实现类?

java中IO流分类:
按照功能分:输入流(Input)、输出流(Output)
按照类型分:字节流、字符流
在这里插入图片描述
在这里插入图片描述

字节流和字符流有什么区别?
区别字节流字符流
传输形式按8位传输,以字节为单位输入输出数据按16位Unicode传输,以字符为单位输入输出数据,基本单元是Unicode码元
是否会用到缓冲区(内存)否,是文件本身直接进行操作的是,通过缓冲区再操作文件的

xhj理解
虽然字符流是按照16位Unicode编码传输的,每次传输的一个字符。
而UTF-8编码,一个中文字符就是3个字节,24位,也就是传输的时候不是传输一个字符

扩展

  • 由于网络传输、文件读写最终的信息的最小保存单位是字节,那么字节是如何解码出字符的呢?
    若干个字节 》 选择某种解码方式 》 解码 》 索引字符集 》 映射到一个字符
  • 不管是网络传输 还是 文件读写,信息的最小保存单位是字节。
  • Unicode和UTF-8的区别:
区别UnicodeUTF-8
定义字符集编码规则
解释为每一个字符分配一个唯一的ID将 “码位”转换为字节序列的规则
中文字符占两个字节占三个字节
java中有几种类型的流?
  • java中所有的流都是基于 字节流。
    字节输入流InputStream、字节输出流OutputStream
  • 封装了 字符流
    字符输入流 Reader、字符输出流 Writer
  • 封装了 缓冲流
    字节流–BufferedInputStream、BufferedOutputStream、PrintStream、字符流–BufferedReader、BufferedWriter
  • 数据流
    DataInputStream、DataOutputStream
  • 对象流
    ObjectInputStream、ObjectOutputStream

多线程

& BIO、NIO、AIO有什么区别?
  • 概念不同:
    BIO是同步阻塞IO、NIO是同步非阻塞式IO、AIO是异步非阻塞式IO。
    BIO表示服务器需要对某个客户端的请求处理完成之后,才能处理别的客户端请求;
    NIO可以用单个线程来监听多个数据通道,核心由通道、缓冲区、选择器组成;
    NIO是线程在IO操作准备好时得到通知,之后由线程自行进行IO操作;
    AIO是在IO操作已经完成后,再给线程通知,因此线程不会因为IO操作阻塞。IO操作完成后,业务逻辑将主动调用一个回调函数通知线程;

  • BIO和NIO区别:

  1. BIO 是以流的方式处理数据,而 NIO 是以块的方式处理数据;
  2. BIO是同步阻塞式,也就是客户端发送请求后,服务端不能确认数据是否有效,此时线程会处于阻塞状态,等待有正确的数据之后才可以执行;NIO是非阻塞式,它会把每个通道注册到选择器上,监控这些通道的I/O状况,当任务完全准备就绪后,会把任务分配给服务器端的一个或多个线程进行处理;
  3. BIO是基于字节流和字符流操作的;NIO是基于通道和缓冲区的,且两者之间的数据传输是双向的;

扩展
Apache(音译为阿帕奇)是世界使用排名第一的Web服务器软件。
Tomcat服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器。是开发和调试JSP 程序的首选。
JSP(Java Server Pages)是一种动态网页技术标准,是用JAVA语言作为脚本语言的。它是软件开发者可以响应客户端请求,并动态生成HTML、XML或其他格式文档的Web网页的技术标准。它和php类似,都是运行在服务端的语言。
nginx 是一个高性能的HTTP和反向代理web服务器,同时提供了IMAP/POP3/SMTP服务。可以在Unix、Linux、OS上编译运行,并且有Windows移植版。
IMPA = Internet Message Access Protocol(互联网邮件访问协议);可以通过这种协议从邮件服务器上获取邮件的信息、下载邮件等;
POP3 = Post Office Rptocol-Version 3 (邮件协议版本3);是TCP/IP协议簇中的一员;主要用于支持使用客户端管理在服务器上的电子邮件;提供了SSL加密的POP3协议称为POP3S;
SMTP = Simple Mail Transfer Protocol(简单邮件传输协议);提供一种可靠且有效的电子邮件传输的协议;是建立在FTP文件传输服务上的一种邮件服务;
Netty 是一个基于NIO的客户、服务器端的编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户、服务端应用。

多线程有几种实现方法,都是什么?

有四种实现方式;
1 继承Thread类的形式,重写run方法;
2 实现Runnable接口的形式,重写run方法;
3 实现Callable和futureTast类,重写call方法;
4 使用Executor 和 ThreadPoolExecutor

sleep() 和 wait() 有什么区别?(面试4更详细)

sleep 和 wait 之间没有任何关系。
sleep() 是Thread类的方法,指的是当前线程暂停。
wait() 是Object类的方法,指的是占用当前对象的线程临时释放对当前对象的占用,以使得其他线程有机会占用当前对象。所以调用wait方法一定是在synchronized中。

简述synchronized和java.util.concurrent.locks.Lock的异同 ?
区别synchronizedLock
概念java中的关键字接口
实现java内置的语言实现代码层面实现
获取锁会一根筋的一直获取下去可以选择性的获取锁,如果一段时间获取不到,可以放弃
避免死锁通过谨慎和良好的设计,才能减少死锁的发生借助它的选择性获得锁,获取不到放弃的性质可以避免死锁
释放锁在发生异常和同步块结束的时候,会自动释放锁lock必须手动释放锁,不释放则会造成死锁
当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法

如果该对象的其他方法也有synchronized修饰,那么其他线程就会被档在外面;
其他线程可以访问其他没有synchronized修饰的方法。

JVM

heap和stack的区别?
区别
名字heapstack
存放内容存放对象存储基本类型(int、boolean等)、引用(对象地址)、方法调用
存取方式自动增加大小,不需要指定大小,但存取相对较慢固定大小,使用FILO先进后出的顺序,并且存取速度比较快
GC是什么?为什么要有GC?

GC,是Garbage Collection的缩写,即垃圾回收。垃圾,指的是那些不再被使用的对象。
垃圾回收机制的好处:
①使得开发人员从无聊、容易犯错的手动释放资源中解放出来;
②使得开发人员更加关注业务功能的开发,资源回收交由垃圾回收机制处理。

垃圾回收的优点和原理?并考虑2种回收机制

优点: C语言中程序员需要手动进行内存资源的释放,java提供垃圾回收机制,自动采用GC,将开发人员从容易犯错的内存资源管理中解放出来。

常见垃圾回收机制

垃圾回收机制介绍弊端
定时回收每隔30分钟进行一次回收如果垃圾产生非常快,在30分钟之内就占满内存,这就会导致系统性能变慢
达到百分比回收当垃圾占到某个百分比的时候,进行回收如果垃圾产生的频率很快,那么JVM就必须高频率的进行垃圾回收,此时JVM会停顿下来,只做垃圾回收,而影响正常的业务。
解析XML文档有几种方式?(有点迷糊)

参考
解析XML文档有四种方式、DOM、SAX、JDOM、DOM4J。
主要是两种:SAX简单应用程序接口和DOM文档对象模型,

DOM
文档对象模型(Document Object Model),是官方推荐的标准,是html和xml文档的编程接口规范,和平台、语言是无关的。
利用DOM规范,能够实现DOM 文档和xml之间的相互转换,遍历、操作相应DOM文档的内容。
DOM规范的核心就是树模型,全部读取之后再解析。
原理是:首先在内存中创建一个Document对象,然后把XML文档读取进来赋值给这个dom对象。由于dom对象是基于树结构的,所以对dom对象进行遍历即可。对内存中的dom对象可以进行查询、修改、删除操作,还可以写回原XML文档保存修改。
优点:由于整棵树在内存中,因此可以对xml文档随机访问;可以对xml文档进行修改操作
缺点:整个文档必须一次性解析完;由于整个文档都需要载入内存,对于大文档成本高
解析过程

1 建立DocumentBuilderFactory
	DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
2 建立 DocumentBuilder
	DocumentBuilder builder = factory.newDocumentBuilder();
3 建立 Document 
	Document doc = builder.parse(“要解析的文件路径”);
4 建立NodeList
	 NodeList nl = doc.getElementsByTagName(“读取节点”);
5 进行XML信息读取

SAX
简单应用程序接口(Simple Api For Xml)。非W3C官方所提供的标准,是一个程序员社区研究出来。
SAX在概念上与DOM完全不同。非文档驱动,是事件驱动的。事件驱动:一种基于回调机制的程序运行方法。由外至内一层一层解析。
优点:解析速度快,占用内存少,它需要哪些数据再加载和解析哪些内容。
缺点:它不会记录标签的关系,而是需要应用程序自己处理,这样就会增加程序的负担。
解析步骤

1 创建解析器工厂
	SAXParserFactory factory = SAXParserFactory.newInstance();
2 获得解析器
	SAXParser parser = factory.newSAXParser();
3 SAX解析器 ,继承 DefaultHandler
	String path = new File("resource/demo01.xml").getAbsolutePath();
4 解析
	parser.parse(path, new MySaxHandler());

JDOM
JDOM是Java和DOM的结合体。JDOM 致力于建立一个完整的基于 Java 平台的、通过 Java 代码来访问、操作并输出 XML 数据。JDOM是用Java语言读、写、操作XML的新API函数。简单、高效、优化。

优点:查找方便,可以修改
缺点:装载整个文档,对内存容量要求高
DOM4J
dom4j是一个Java的XML API,类似于jdom,用来读写XML文件的。性能优异、功能强大、简单易用的开放源代码。
它是目前最流行、最好用的XML解析工具,解析XML的速度最快。
操作步骤:

1 创建SAXReader
	SAXReader reader = new SAXReader();
2 创建文件输入流打开xml文件
	InputStream in = new FileInputStream("XXX.xml");
3 通过reader和输入流读取xml文件到内存创建Document对象
	Document dom = reader.read(in);
4 获取根节点
	Element root=dom.getRootElement();
5 获取子节点列表
	List< Element > childNodes = root.elements();
6 遍历子节点
	Element node = childNodes.get(i);
7 读取结点信息:
	结点属性值:node.attributeValue("属性名");
	结点名:node.getName();
	结点值:node.getValue();
	子结点文本值:node.elementText("子结点名")

扩展

  • XML概述
    XML即可扩展的标记语言,可以定义语义标记(标签),是元标记语言。
    XML不像超文本标记语言HTML,HTML只能使用规定的标记语言。对于XML,用户可以定义自己需要的标记。树状模型。
    XML文档以层级标签的形式来组织数据,多用于配置文件、存储静态数据、交换数据。
  • 为什么要解析XML文件?以及什么情况下需要对XML文件解析?
    XML 本身来讲就是用来进行不同语言之间通信用的。其实可以把XML当做一种数据存储方式,比数据库灵活。
    大部分情况下,数据要存储在数据库中,但是一些经常用到且重要的内容(比如权限),希望随时更改且保证安全,那么就需要存储到XML中。
java中会存在内存泄漏吗,请简单描述。

因为java是自动进行垃圾回收管理的,所以不存在C语言中同等概念的内存泄露,但是会存在java特色的内存泄露。
java中的内存泄露 = 当某些对象不被使用,但是又有非直接引用指向的时候,那么久不满足垃圾回收的条件,就会导致内存泄露。
案例解释:

 	static ArrayList<Object> al = new ArrayList<Object>();
 	public static void main(String[] args) {
      for (int i = 0; i < 100; i++) {
          Object o = new Object();
          al.add(o);
      }
      // 分析:
      每个object对象创建的时候,都会有引用o指向,接着放入ArrayList集合中,下一个Object创建的时候,上一个Object就没有引用指向了。而ArrayList忘记了回收,那么里面的所有对象,都会一直存活下去,虽然不再被使用。
    }

扩展
C语言中的内存泄露问题:
只有在堆内存里面才会发生内存泄露的问题,在栈内存中不会发生内存泄露。
因为栈内存存在自动分配空间之后,还会自动释放空间。

数据连接池的工作机制是什么?

数据库连接池原理:
创建连接和关闭连接的行为是非常耗时的,会显著降低软件的性能表现。
解决思路是:先创建n条数据库连接Connection,循环使用,但是不进行关闭,这样再执行SQL语句,就不需要额外创建连接,直接使用即可,从而节省了创建连接和关闭连接的时间。

Class.forName(“参数”)的作用?为什么要用?

作用:按照参数中指定的字符串形式的类名去搜索并加载相应的类。

  • 如果该类字节码已经被加载过了,则返回代表该字节码的Class实例对象。
  • 按类加载器的委托机制去搜索和加载该类,如果所有的类加载器都无法加载到该类,则抛出ClassNotFoundException。

使用的原因:
我们程序中所有使用的具体类名在设计时无法确定,只有程序运行时才能确定,这时候就需要使用Class.forName去动态加载该类,只有程序运行时才能确定。

java的运行机制描述?

ClassLoader是JVM实现的一部分
Java虚拟机逐行读取并执行.class文件
java编译器会将程序编辑为java虚拟机可以执行的字节码文件
java虚拟机(Java Virtual Machine),简称JVM 用于执行java字节码
java运行时环境(Java Runntime Evironment)简称JRE,用于运行java程序 包含JVM
java开发工具包(Java Development Kit)用于开发java程序,包含JRE和java编译工具等。

流程控制

在java中,如何跳出当前的多重嵌套循环?

在外部循环的前一行,加上标签。
在break的时候使用该标签,即能达到结束多重嵌套循环效果。

// idea_face-test3-
public class breakDemo {
 public static void main(String[] args){
        outloop:
        for(int i = 0 ; i < 10;i++){
            for(int j = 0 ; j < 10 ;j++){
                System.out.println(i + ":" + j);
                if(j%2 == 0){
                    break outloop;
                }
            }
            //预判输出结果:0:0
        }
    }
   }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值