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开发人员使用的,其中包含了jJava的开发工具,也包含了JRE。所以安装JDK,也就无需单独安装JRE了。其中的开发工具:编译工具(javac.exe),打包工具(jar.exe)
2、数组与链表的区别
物理地址存储的连续性
数组元素在内存中是连续存放的。
链表元素在内存中不一定是连续存放的
访问速度
数组的访问速度很快,因为数组可以很具数组下标进行快速定位。
链表的访问速度较慢,因为链表访问元素需要移动指针
添加、删减元素速度
数组的元素增删速度较慢,因为需要移动大量的元素
链表的元素增删速度较快,因为只需要修改指针即可。
数组必须事先定义好固定的长度,而链表可以动态的进行存储分配
3、接口和抽象类的区别,以及各自的使用场景
抽象类:包含抽象方法的类,即使用abstract修饰的类;不能用final修饰,final修饰的类不能被继承;抽象类不能被实例化,只能被继承。
接口:接口是一个人抽象类型,是抽象方法的集合,接口以 interface 来声明。一个类通过即成为那个接口的方式,从而继承接口的抽象方法;接口只能继承接口,不能继承类,接口支持多继承。接口中的定义的成员变量,默认是 public static final 修饰的静态常量;
相同点 :
抽象类和接口都不能被实例化
抽象类和接口都可以定义抽象方法,子类/实现类必须覆写这些抽象方法
不同点:
抽象类有构造方法,接口没有构造方法
抽象类可以包含普通方法,接口中只能是public abstract 修饰抽象方法
抽象类只能单继承,接口可以多继承
抽象类可以定义各种类型的成员变量,接口中只能是public static final 修饰的静态变量
抽象类的使用场景:
既想约束子类具有共同的行为,又想拥有缺省的方法,又能拥有实例变量
接口的应用场景:
约束多个实习类具有统一的行为,但是不在乎每个实现类如何具体实现;实现类需要具备不同的功能,但各个功能更之间可能没有任何联系
设计一个报警门继承Door类和实现Alarm接口
interface Alram {
void alarm();
}
abstract class Door {
void open();
void close();
}
class AlarmDoor extends Door implements Alarm {
void oepn() {
//....
}
void close() {
//....
}
void alarm() {
//....
}
}
抽象类和接口不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象。
抽象类要被子类继承,接口要被类实现
抽象类能使用final修饰吗?
不能,定义的抽象类就是让其他类继承的,如果定义为final该类就不能被继承,这样彼此间就产生矛盾,所以final不能修饰抽象类。
4、Java面向对象的特性封装、继承、多态、与C++区别
特性:封装、继承、多态
封装:隐藏对象的属性和实现细节,对外提供公共的访问方式,以防止数据的随意访问和修改Get和Set方法
继承:继承是类与类的有一种关系,子类拥有父类的所有属性和方法(除了PRIVATE修饰的属性不能拥有)从而实现了代码的复用
多态:多态就是允许不同类的对象对同一消息做出响应。就是指一个引用类型在不同情况下的多种非状态三个条件满足继承关系、父类引用变量指向子类对象、子类重写父类的方法
相同点:都是面向对象语言,并且支持封装、继承、多态
不同点:C++支持多态继承 ,并且有指针的概念,由程序员自己管理内存;Java是单继承,可以用接口实现单继承,java不提供指针来直接访问内存,程序内存更加安全,并且Java有JVM自动内存管理机制,不需要程序员手动释放无用内存
5、面向对象的设计原则?
单一职责原则
开闭原则
里氏代换原则
合成复用原则
依赖倒转原则
迪米特法则
多态的实现
虚拟机栈中会存放当前方法调用的栈帧(局部变量表,操作栈、动态连接、返回地址)。多态的实现过程,就是方法调用动态分配的过程,通过栈帧的信息去找到被调用方法的具体实现,然后使用这个具体实现的直接引用完成方法调用。
以invokevirtual指令为例,在执行时大致可以分为以下几步:
先从操作栈中找到对象的实际类型class;
找到class中与被调用方法签名相同的方法,如果有访问权限就返回这个方法的直接引用,如果没有访问权限就报错java.lang.IllegalAccessError;
如果第二步找不到相符的方法,就去搜索class的父类,按照继承关系自下而上一次执行第二步操作;
如果第三步找不到相符的方法,就报错java.lang.AbstractMethodError;
子类覆盖父类的方法,则在多态调用中,动态绑定过程会首先确定实际类型是子类,从而先搜索到子类中的方法。这个过程表示方法覆盖的本质
静态绑定和动态绑定
静态代理和动态代理
代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。值得注意的是,代理类和被代理类应该共同实现一个接口,或者是共同继承某个类
静态代理:代理类是手工实现的java文件,同时代理的目标对象是规定的
优点:容易理解,使用方便。缺点:在目标类比较多的时候,会产生大量的代理类;当接口改变是,会影响目标类
动态代理:代理对象在程序运行时由JVM根据反射机制动态生成的。动态代理不需要定义代理类的.java源文件
优点:不用创建代理类,可以给不同的目标随时创建代理。缺点:JDK动态代理不需要任何外部依赖、但是它只是基于接口进行代理(因为继承了proxy,java不支持多继承)。CGLIB通过继承的方式进行代理、无论目标对象有没有实现接口都可以代理,但是无法处理final的情况(final修饰的方法不能被覆写)
泛型以及泛型擦除。List类型的list,可以加入无继承关系的B类型对象吗?如何加入?
ArrayList<String> list1 = new ArrayList<String>();
list1.add("abc");
ArrayList<Integer> list2 = new ArrayList<Integer>();
list2.add(123);
泛型:
泛型提供了编译时类型安全监测机制,该机制语序程序员在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型是以用在l类、接口和方法的创建中,分别称为泛型类、泛型接口和泛型方法。
泛型擦除
JAVA的泛型是伪泛型,是因为java在编译期间,所有的泛型信息都会被擦掉,正确立即接泛型概念的首要前提是理解类型擦除。Java的泛型基本上都是在编译器这个层次上实现的,而生成的字节码不包含泛型中的类型信息的,使用泛型的时候加上类型参数,在编译器编译的时候会去电,这个过程称为泛型擦除。
如在代码中定义List<object>和List<string>等类型,在编译之后都会变成List。JVM看到的只是List,而由反省附加的类型信息对jvm来说是不可见的。
操作字符串都有哪些类?区别是什么?
操作字符串的类有:String、StringBuffer、StringBuilder
String和StringBuffer、StringBuffer的区别在于String 声明的是不可变的对象,每次操作都会生成新的String对象,然后对指针指向新的String对象,而StringBuffer、StringBuilder可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用String。
StringBuffer和StringBuilder最大的区别在于StringBuffer是线程安全的,而StringBuilder是非线程安全的,但StringBuilder的性能却高于StringBuffer,所以在单线程环境下推荐使用StringBuilder,多线程环境下推荐使用StringBuffer。
String str="i"与 String str=new String(“i”)一样吗?
不一样,因为内存分配的方式不一样。String str="i"的方式,Java虚拟机将其分配到常量池中;而
String str=new String(“i”)则会被分到堆内存中。
如何将字符串反转:使用 StringBuilder 或者 stringBuffer的reverse()方法
字符串常用的方法
indexOf():返回指定字符的索引
charAt():返回指定索引处的字符
replace():字符串替换
replace(char searchChar, char newChar)
trim():去除字符串两端空白
split():分割字符串,返回一个分割后的字符串数组。
split(String regex, int limit) regex -- 正则表达式分隔符 limit -- 分割的份数
getBytes():返回字符串的byte类型数组。使用平台的默认字符集将字符串编码为 byte 序列
length():返回字符串长度
toLowerCase():将字符串转换成小写字母
toUpperCase():将字符串转换成大写字符
substring():截取字符串
public String substring(int beginIndex, int endIndex) beginIndex -- 起始索引(包括), 索引从 0 开始。endIndex -- 结束索引(不包括)
equals():字符串比较
Java的异常体系
Throwable是Java语言中所有错误或异常的超类。下一层分为Error和Exception 。
Error:是指JAVA运行时系统的内部错误和资源耗尽错误。应用程序不会抛出该类对象。
Exception包含:RuntimeException 、CheckedException
反射原理以及使用场景
Java反射:是指在运行状态中,对任意一个类都能够知道这个类所有的属性和方法;并且对于任意一个对象,都能够调用它的任意一个方法;这种动态获取信息以及调用对象方法的功能成为java语言的反射机制
反射原理:反射首先是能够获取到java中的反射类的字节码,然后将字节码中的方法,变量,构造函数等映射成相应的Method、Filed、Constructor
类名。class(就是一份字节码)
Class.forName(String className);根据一个类的全限定名来构建Class对象
每个对象都有getClass()方法;obj.getClass();返回对象的真是类型
使用场景:
逆向代码,例如反编译:
动态生成框架,如Spring:XML的配置模式。Spring通过XML配置模式装载Bean的过程:1)将程序内所有XML或Properties配置文件加载内存中;2)Java类里面解析xml或properties里面的内容,得到对应实体类的字节码字符串以及相关的属性信息;3)使用反射机制,根据这个字符串获取某个类的Class实例;4)动态配置实例的属性
ThreadLocal原理,如何使用???
ThreadLocal简介:
通常情况下,创建的变量是可以被任何一个线程访问并被修改的。如果想实现每一个线程都有自己专属本地变量该如何解决?JDK中提供的ThreadLocal类正是解决这样的问题。
原理:首先ThreadLocal是一个泛型类,保证可以接受任何类型的对象。因为一个线程内可以对ThreadLocal象,所以其实是ThreadLocal内部维护了一个Map,这个Map不是直接使用的HashMap,而是ThreadLocal实现的一个叫做ThreadLocalMap的静态内部类。
最终的变量是放在当前线程ThreadLocalMap中,并不是存在ThreadLocal上,ThreadLocal可以理解为只是ThreadLocalMap的封装,传递了变量值。
ThreadLocal内存泄漏的场景??
static关键字和final关键字使用情况,一个类不能被继承,除了final关键字之外,还有什么方法(从构造函数考虑)?
static:可以修饰属性、方法
static修饰属性:
所有对象共享一份,一个对象对其修改,其他的调用也会受到影响,类级别:随着类的加载二加载(只加载一次),先于对象的创建;可以使用类名直接调用。
static修饰方法:
随着类的加载而加载,可以使用类名直接调用:静态方法中,只能调用静态成员;非静态的方法中,可以调用静态和非静态的成员;静态方法中,不会出现this。
final:可以修饰变量、方法、类
final修饰变量:
对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在其对初始化后便不能再让其指向另一个对象。
final修饰方法:
把方法锁定,以防任何继承类修改它的含义(重写);类中所有的private方法都隐式地指定为final
final修饰类:
fina修饰类时,表明这个类不能被继承。final类中的所有成员方法都会被隐式地指定为fianl方法
final finally 和 finalize的区别
final用于声明属性,方法和类,分别表示属性不可便,方法不可覆盖,类不可继承。finally是异常处理语句结构的一部分,表示总是执行。finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,供垃圾收集时的其他资源回收,例如关闭文件。
被final修饰符(关键字)
被final修饰的类,就意味着不能派生出新的子类,不呢个作为弗雷而被子类继承。因此一个类不能既被abstract声明,又被final声明。将变量或方法声明为final,可以保证他们在使用过程中不被修改。
finallly是在异常处理时提供finally块来执行任何清楚操作、
不管有没有异常被抛出、捕获,finally块都会被执行。try块中的内容是在无异常执行到结束。catch块中的内容,是在try块内容发生catch所声明的异常时,跳转到catch中执行。
finalize是方法名
java技术允许使用finalize方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确当这个对象有没有被引用时对这个对象调用的。它是在object类中定义的。因此所有的类都被继承它。子类覆盖finalize方法以整理系统资源或者被执行其他清理工作。