Java基础

1. String、StringBuffer、StringBuilder之间的区别;

String 和 StringBuffer、StringBuilder 的区别在于 String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象,而 StringBuffer、StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。
StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的,但 StringBuilder 的性能却高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。

2. String 类的常用方法都有那些?

indexOf():返回指定字符的索引。
charAt():返回指定索引处的字符。
replace():字符串替换。
trim():去除字符串两端空白。
split():分割字符串,返回一个分割后的字符串数组。
getBytes():返回字符串的 byte 类型数组。
length():返回字符串长度。
toLowerCase():将字符串转成小写字母。
toUpperCase():将字符串转成大写字符。
substring():截取字符串。
equals():字符串比较。

3.String能被继承吗?为什么

不可以,因为String类有final修饰符,而final修饰的类是不能被继承的,实现细节不允许改变。平常我们定义的String str=”abc”(直接赋一个字面量);其实和String str=new String(“abc”)(通过构造器构造)还是有差异的。


2.png

String str=“abc”和String str=new String(“abc”); 产生几个对象?

  • 前者1或0,后者2或1,先看字符串常量池,如果字符串常量池中没有,都在常量池中创建一个,如果有,前者直接引用,后者在堆内存中还需创建一个“abc”实例对象。
  • 对于基础类型的变量和常量:变量和引用存储在栈中,常量存储在常量池中。
  • 为了提升jvm(JAVA虚拟机)性能和减少内存开销,避免字符的重复创建 项目中还是不要使用new String去创建字符串,最好使用String直接赋值。

3.抽象类和接口的区别,类可以继承多个类么,接口可以继承多个接口么,类可以实现多个接口么。

  • 抽象类和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象。
  • 抽象类要被子类继承,接口要被类实现。
  • 接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。
  • 抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,一个实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类。
  • 抽象方法只能申明,不能实现。abstract void abc();不能写成abstract void abc(){}。
  • 抽象类里可以没有抽象方法
  • 如果一个类里有抽象方法,那么这个类只能是抽象类
  • 接口只能做方法申明,抽象类中可以做方法申明,也可以做方法实现
  • 抽象方法要被实现,所以不能是静态的,也不能是私有的。
  • 接口可继承接口,并可多继承接口,但类只能单根继承。

另:

  • 抽象类:抽象类必须用 abstract 修饰,子类必须实现抽象类中的抽象方法,如果有未实现的,那么子类也必须用 abstract 修饰。抽象类默认的权限修饰符为 public,可以定义为 public 或 procted,如果定义为 private,那么子类则无法继承。抽象类不能创建对象
    抽象类和普通类的区别
    抽象类必须用public、procted 修饰(如果为private修饰,那么子类则无法继承,也就无法实现其抽象方法)。默认缺省为 public
    抽象类无法创建对象
    如果一个子类继承抽象类,那么必须实现其所有的抽象方法。如果有未实现的抽象方法,那么必须定义为 abstract

  • 接口:接口中的变量隐式的使用 public static final 修饰,并且需要给出初始值。方法隐式的使用 public abstract 修饰(并且只能是 public ,如果是 private,procted,那么就编译报错)。接口中的方法默认不能有具体的实现(JDK1.8开始可以有默认的实现)

  • 接口和抽象类的区别:抽象类只能继承一次,但是可以实现多个接口
    接口和抽象类必须实现其中所有的方法,抽象类中如果有未实现的抽象方法,那么子类也需要定义为抽象类。抽象类中可以有非抽象的方法
    接口中的变量必须用 public static final 修饰,并且需要给出初始值。所以实现类不能重新定义,也不能改变其值。
    接口中的方法默认是 public abstract,也只能是这个类型。不能是 static,接口中的方法也不允许子类覆写,抽象类中允许有static 的方法

4.final 的用途

修饰类、变量、方法
final 修饰的类叫最终类,该类不能被继承。
final 修饰的方法不能被重写。
final 修饰的变量叫常量,常量必须初始化,初始化之后值就不能被修改。

5.synchronized 和 volatile 的区别是什么?

volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的。
volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性。
volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化。

6. JDK 和 JRE 有什么区别?

JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境。
JRE:Java Runtime Environment 的简称,java 运行环境,为 java 的运行提供了所需环境。
具体来说 JDK 其实包含了 JRE,同时还包含了编译 java 源码的编译器 javac,还包含了很多 java 程序调试和分析的工具。简单来说:如果你需要运行 java 程序,只需安装 JRE 就可以了,如果你需要编写 java 程序,需要安装 JDK。

7.== 和 equals 的区别是什么?

== 解读:
对于基本类型和引用类型 == 的作用效果是不同的,如下所示:
基本类型:比较的是值是否相同;
引用类型:比较的是引用是否相同;
equals 解读:
equals 本质上就是 ==,只不过 String 和 Integer 等重写了 equals 方法,把它变成了值比较。看下面的代码就明白了。
首先来看默认情况下 equals 比较一个(有相同值的对象),

String x = "string";
String y = "string";
String z = new String("string");
System.out.println(x==y); // true,引用相同
System.out.println(x==z); // false,==:string比较引用,开辟了新的堆内存空间,所以false
System.out.println(x.equals(y)); // true,equals:string:比较值,相同
System.out.println(x.equals(z)); // true,equals:string比较值,相同

总结 :== 对于基本类型来说是值比较(不难理解,八种基本数据类型是可以有确定值的),对于引用类型来说是比较的是引用(数组、类、接口没有确定值);而 equals 默认情况下是引用比较,只是很多类重新了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。

8.Java中的异常有哪几类?分别怎么使用?

异常类有分为编译时异常和运行时异常

  • 编译时异常:写代码的时候就会提醒你有异常,常见的编译时异常有:
IOException
SQLException
CloneNotSupportedException
parseException
  • 运行时异常:java.lang.RuntimeException,运行的时候会在控制台提示异常,常见的运行时异常有:
            NullPointerException: 空指针异常,一般出现于数组,空对象的变量和方法
            ArrayIndexOutOfBoundsException: 数组越界异常
            ArrayStoreException: 数据存储异常
            NoClassDefFoundException: java运行时系统找不到所引用的类
            ArithmeticException: 算数异常,一般在被除数是0中
            ClassCastException: 类型转换异常
            IllegalArgumentException: 非法参数异常
            IllegalThreadStateException: 非法线程状态异常
            NumberFormatException: 数据格式异常
            OutOfMemoryException: 内存溢出异常
            PatternSyntaxException: 正则异常
  • 怎么使用:
    一种是在方法中声名异常,谁调用就把异常抛给谁
    一种是使用try{}..catch{}块处理异常
    如果多个异常处理的方式不同,可以用多个catch处理
    如果所有异常处理方式一样,可以捕获一个父类异常进行统一的处理
    如果多个异常分成了不同的组,那么同一组异常之间可以使用|隔开(jdk1.7开始)
    jdk1.7还增加了增强tr(){}catch(){},通常用于自动关流
  • 异常知识扩展:
    Throwable类是所有异常的超类,有两个子类,分为Error和Exception
    Error:错误是无法处理的,只能更改代码,就像一个人得癌症一样
    Exception:异常是可以处理的,就像是感冒一样,吃药就能好
    在方法重写的时候
    子类抛出的编译时异常不能超过父类编译时异常范围
    子类不能抛出比父类更多的编译时异常(这里是指抛出异常的范围不能更大,但个数可以更多)
    编译时异常随你抛

9.内存溢出是怎么回事?请举一个例子?

Java内存溢出(内存泄漏)
内存溢出(out of memory)通俗理解就是内存不够,在计算机程序中通俗的理解就是开辟的内存空间得不到释放。Java虽然提供了垃圾回收机制,但是并没有保证我们所写的代码就不存在没存溢出的可能

import java.util.ArrayList;
import java.util.List;
public  class MyList{
  // 此处只为掩饰效果,并没有进行封装之类的操作
   //将List集合用关键字 static 声明,这时这个集合将不属于任何  MyList 对象,而是一个类成员变量
   public static List list = new ArrayList();
}
class Demmo{
    public static void main(String[] args) {
        MyList list = new MyList();
        list.list.add("123456");
        // 此时即便我们将 list指向null,仍然存在内存泄漏,因为MyList中的list是静态的,它属于类所有而不属于任何特定的实例
        list = null;
    }
}

上面的情况如果想要防止内存溢出,那么我们应该做的是,在每次使用完后调用List集合中的remove方法,将集合中无用的元素清除。
还有就是,既然是static变量就别要使用类对象去调用啦,使用实例对象调用static变量可能引发一些意想不到的后果哦!
内存溢出分三种情况

  • OutOfMemoryError: PermGen space
    Permanent Generation space 这个区域主要用来保存加来的Class的一些信息,在程序运行期间属于永久占用的,Java的GC不会对他进行释放,所以如果启动的程序加载的信息比较大,超出了这个空间的大小,就会发生溢出错误;
    解决的办法无非就是增加空间分配了——增加java虚拟机中的XX:PermSize和XX:MaxPermSize参数的大小,其中XX:PermSize是初始永久保存区域大小,XX:MaxPermSize是最大永久保存区域大小。
  • OutOfMemoryError:Java heap space
    heap 是Java内存中的堆区,主要用来存放对象,当对象太多超出了空间大小,GC又来不及释放的时候,就会发生溢出错误。
    Java中对象的创建是可控的,但是对象的回收是由GC自动的,一般来说,当已存在对象没有引用(即不可达)的时候,GC就会定时的来回收对象,释放空间。但是因为程序的设计问题,导致对象可达但是又没有用(即前文提到的内存泄露),当这种情况越来越多的时候,问题就来了。
    针对这个问题,我们需要做一下两点:
    (1)、检查程序,减少大量重复创建对象的死循环,减少内存泄露。
    (2)、增加Java虚拟机中Xms(初始堆大小)和Xmx(最大堆大小)参数的大小。
  • StackOverFlowError
    stack是Java内存中的栈空间,主要用来存放方法中的变量,参数等临时性的数据的,发生溢出一般是因为分配空间太小,或是执行的方法递归层数太多创建了占用了太多栈帧导致溢出。
    针对这个问题,除了修改配置参数-Xss参数增加线程栈大小之外,优化程序是尤其重要。

10.JVM内存结构,为什么需要GC?

11.Files的常用方法有哪些?

  • Files.exists() 检测文件路径是否存在
  • Files.createFile()创建文件
  • Files.createDirectory()创建文件夹
  • Files.delete() 删除文件或者目录
  • Files.copy() 复制文件
  • Files.move() 移动文件
  • Files.size() 查看文件个数
  • Files.read() 读取文件
  • Files.write()写入文件

你可能感兴趣的:(Java基础)