声明:题目来源于Java后端公众号,但是答案皆为个人整理,仅供参考。
-
面向对象的特征:继承、封装和多态
- 继承:多个类具有共同的属性(成员变量)与行为(成员方法)的时候,将这些共同的部分抽取出来定义到一个公共的类中,其他及各类可以与这个公共的类形成继承关系,从而在多个类中不需要重 复定义公共部分!这个公共的类就是父类,也称为超类或者基类,其他的类就是子类。子类可以直接访问父类的非私有化成员变量,访问父类的私有化成员变量可以使用super.get()方法。
- 封装:所谓封装指的是隐藏对象的属性以及实现细节,仅对外提供访问方式,将不需要对外提供的内容进行隐藏,把属性隐藏对外提供访问方式。使用private修饰。
- 多态: java程序中定义的引用变量所指向的具体类型和通过该引用类型发出的方法在调用时不确定,该引用变量发出的方法到底调用哪个类的实现的方法,必须在程序运行期间才能决定。
- 多态的成员特点:成员变量:编译与运行时期都看父类!
成员方法:编译时期看父类,运行时期看子类
- 多态的成员特点:成员变量:编译与运行时期都看父类!
-
final, finally, finalize 的区别
- final:Java的关键字之一,被final修饰的类不能被继承,所以要注意一个类不能被abstract和final同时修饰;被final修饰的变量不能被修改,所以一开始要先赋值。当final修饰的成员变量为引用数据类型时,在赋值后其指向地址无法改变,但是对象内容还是可以改变的。
- finally:捕获异常中的finally模块,不管有没有异常被抛出、捕获,finally块都会被执行。
-
finally什么时候会被执行:
- 在try...catch...finally语句中,只要try语句之前程序没有抛异常,或者在try语句中程序没有退出(System.exit(0))的话,就会执行;
- 加入try语句中有return语句,那么会先执行finally语句中的内容,因为如果执行了return语句程序就会结束退出;
- 此外,要注意方法内部的变量都是存放在栈里面,函数执行结束后,其对应的栈会被回收,那么方法体中定义的变量也就不存在了,所以return语句实际上是拷贝了一份值,然后再返回的。所以在finally中如果有return语句的话,对基本类型的值不影响,但是对引用类型的值就会有影响。
-
- finalize:这是Object类中的一个方法,在gc启动,该对象被回收的时候被调用。其实gc可以回收大部分的对象(凡是new出来的对象,gc都能搞定,一般情况下我们又不会用new以外的方式去创建对象),所以一般是不需要程序员去实现finalize的。 一个对象的finalize()方法只会被调用一次,而且finalize()被调用不意味着gc会立即回收该对象,它与析构函数不同。
-
Exception、Error、运行时异常与一般异常有何异同
- Exception:分为两个分支:一个分支派生于RuntimeException;另一个分支包含其他异常。划分两个分支的规则是:由程序错误导致的异常属于RuntimeException;而程序本身没有没有问题,但由于像I/O错误这类异常导致的异常属于其他异常。
IOException(其他异常)
FileNotFoundException(文件未找到异常。)
IOException(操作输入流和输出流时可能出现的异常。)
EOFException (文件已结束异常) - Error:描述了java运行时系统的内部错误和资源耗尽错误。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。应用程序不应该抛出这种类型的对象。
- 运行时异常:对于运行时异常,java编译器不要求必须进行异常捕获处理或者抛出声明,由程序员自行决定。
- Exception:分为两个分支:一个分支派生于RuntimeException;另一个分支包含其他异常。划分两个分支的规则是:由程序错误导致的异常属于RuntimeException;而程序本身没有没有问题,但由于像I/O错误这类异常导致的异常属于其他异常。
-
请写出5种常见到的runtime exception
- IndexOutOfBoundsException(下标越界异常)
- NullPointerException(空指针异常)
- NumberFormatException (String转换为指定的数字类型异常)
- ArithmeticException -(算术运算异常 如除数为0)
- ArrayStoreException - (向数组中存放与声明类型不兼容对象异常)
- SecurityException -(安全异常)
-
int 和 Integer 有什么区别,Integer的值缓存范围https://blog.csdn.net/why15732625998/article/details/79437930#commentBox
- Integer是int的包装类;int是基本数据类型;
- Integer变量必须实例化后才能使用;int变量不需要;
- Integer实际是对象的引用,指向此new的Integer对象;int是直接存储数据值 ;
- Integer的默认值是null;int的默认值是0。
- 由于Integer变量实际上是对一个Integer对象的引用,所以两个通过new生成的Integer变量永远是不相等的(因为new生成的是两个对象,其内存地址不同)。
- Integer变量和int变量比较时,只要两个变量的值是向等的,则结果为true(因为包装类Integer和基本数据类型int比较时,java会自动拆包装为int,然后进行比较,实际上就变为两个int变量的比较)
- 非new生成的Integer变量和new Integer()生成的变量比较时,结果为false。(因为非new生成的Integer变量指向的是java常量池中的对象,而new Integer()生成的变量指向堆中新建的对象,两者在内存中的地址不同)
- 对于两个非new生成的Integer对象,进行比较时,如果两个变量的值在区间-128到127之间,则比较结果为true,如果两个变量的值不在此区间,则比较结果为false
- 深入描述
-
public class Test { public static void main(String[] args) { //在-128~127 之外的数 Integer num1 = 128; Integer num2 = 128; System.out.println(num1==num2); //false // 在-128~127 之内的数 Integer num3 = 9; Integer num4 = 9; System.out.println(num3==num4); //true } }
解析原因:归结于java对于Integer与int的自动装箱与拆箱的设计,是一种模式:叫享元模式(flyweight)。
加大对简单数字的重利用,Java定义在自动装箱时对于值从–128到127之间的值,它们被装箱为Integer对象后,会存在内存中被重用,始终只存在一个对象。
而如果超过了从–128到127之间的值,被装箱后的Integer对象并不会被重用,即相当于每次装箱时都新建一个 Integer对象。
-
- 源码分析:
- 给一个Integer对象赋一个int值的时候,会调用Integer类的静态方法valueOf,源码如下:
-
public static Integer valueOf(String s, int radix) throws NumberFormatException { return Integer.valueOf(parseInt(s,radix)); } public static Integer valueOf(int i) { assert IntegerCache.high >= 127; if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
- IntegerCache是Integer的内部类,源码如下:
/** * 缓存支持自动装箱的对象标识语义 * -128和127(含)。 * * 缓存在第一次使用时初始化。 缓存的大小 * 可以由-XX:AutoBoxCacheMax = <size>选项控制。 * 在VM初始化期间,java.lang.Integer.IntegerCache.high属性 * 可以设置并保存在私有系统属性中 */ private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); } private IntegerCache() {} }
-
包装类,装箱和拆箱
- 每个包装类的对象可以封装一个相应的基本类型的数据,并提供了其它一些有用的方法。包装类对象一经创建,其内容(所封装的基本类型数据值)不可改变。
-
基本类型和对应的包装类可以相互装换:
- 由基本类型向对应的包装类转换称为装箱,例如把 int 包装成 Integer 类的对象;
- 包装类向对应的基本类型转换称为拆箱,例如把 Integer 类的对象重新简化为 int。
-
String、StringBuilder、StringBuffer
- 在这方面运行速度快慢为:StringBuilder > StringBuffer > String。效率比较String<StringBuffer<StringBuilder,操作的数据量小的时候可以用String。
- String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。
-
String str="abc"; System.out.println(str); str=str+"de"; System.out.println(str);
如果运行这段代码会发现先输出“abc”,然后又输出“abcde”,好像是str这个对象被更改了,其实,这只是一种假象罢了,JVM对于这几行代码是这样处理的,首先创建一个String对象str,并把“abc”赋值给str,然后在第三行中,其实JVM又创建了一个新的对象也名为str,然后再把原来的str的值和“de”加起来再赋值给新的str,而原来的str就会被JVM的垃圾回收机制(GC)给回收掉了,所以,str实际上并没有被更改,也就是前面说的String对象一旦创建之后就不可更改了。所以,Java中对String对象进行的操作实际上是一个不断创建新的对象并且将旧的对象回收的一个过程,所以执行速度很慢。而StringBuilder和StringBuffer的对象是变量,对变量进行操作就是直接对该对象进行更改,而不进行创建和回收的操作,所以速度要比String快很多。另外,有时候我们会这样对字符串进行赋值。
-
String str="abc"+"de"; StringBuilder stringBuilder=new StringBuilder().append("abc").append("de"); System.out.println(str); System.out.println(stringBuilder.toString());
这样输出结果也是“abcde”和“abcde”,但是String的速度却比StringBuilder的反应速度要快很多,这是因为第1行中的操作和String str="abcde";是完全一样的,所以会很快,而如果写成下面这种形式:
-
String str1="abc"; String str2="de"; String str=str1+str2;
那么JVM就会像上面说的那样,不断的创建、回收对象来进行这个操作了。速度就会很慢。
- 线程安全:StringBuilder是线程不安全的,而StringBuffer是线程安全的
- 如果一个StringBuffer对象在字符串缓冲区被多个线程使用时,StringBuffer中很多方法可以带有synchronized关键字,所以可以保证线程是安全的,但StringBuilder的方法则没有该关键字,所以不能保证线程安全,有可能会出现一些错误的操作。所以如果要进行的操作是多线程的,那么就要使用StringBuffer,但是在单线程的情况下,还是建议使用速度比较快的StringBuilder。
-
String:适用于少量的字符串操作的情况
StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况
StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况
- 在这方面运行速度快慢为:StringBuilder > StringBuffer > String。效率比较String<StringBuffer<StringBuilder,操作的数据量小的时候可以用String。
-
重载和重写的区别
https://blog.csdn.net/Andya_net/article/details/76815259
- 重载是让类以统一的方式处理不同类型数据的一种手段。多个同名函数同时存在,具有不同的参数个数/类型,是一个类中多态性的一种表现。重载的规则:
-
必须具有不同的参数列表;
-
可以有不同的返回类型,只要参数列表不同就可以了;
-
可以有不同的访问修饰符;可以抛出不同的异常;
-
- 重写要求返回值、方法名和参数都相同,子类抛出的异常不能超过父类相应方法抛出的异常。(子类异常不能超出父类异常);子类方法的的访问级别不能低于父类相应方法的访问级别(子类访问级别不能低于父类访问级别)。重写的规则:
- 参数列表必须完全与被重写的方法相同,否则不能称其为重写而是重载。
- 返回的类型必须一直与被重写的方法的返回类型相同,否则不能称其为重写而是重载。
- 访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private)
- 重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常。例如:
- 父类的一个方法申明了一个检查异常IOException,在重写这个方法是就不能抛出Exception,只能抛出IOException的子类异常,可以抛出非检查异常。
- 重载是让类以统一的方式处理不同类型数据的一种手段。多个同名函数同时存在,具有不同的参数个数/类型,是一个类中多态性的一种表现。重载的规则:
-
抽象类和接口有什么区别
- 抽象类由abstract关键字修饰,不能被private修饰,因为抽象类不能实例化,需要被继承,所以抽象类也不能被final修饰;
- 接口中定义了一些动作(即方法),接口中的方法默认为public abstract,可以含有变量,但是接口中的变量默认为public abstract final。
接口修饰符只能用public、default和abstract。 不能用final、static修饰。在jdk1.8之后,可以用static修饰方法了。
-
相同点:都不能被实例化;接口的实现类或者抽象类的子类都只有实现了接口或抽象类中的方法才能被实例化
-
不同点:
- 接口只能定义方法,抽象类中可以定义和实现接口需要实现,
- 抽象类需要继承,一个类可以实现多个接口但只能继承一个类
- 接口中成员变量是public static final,只能有静态的不能被修改的数据,必须赋值,所有的方法都是public abstract,而且只能被这两个修饰。抽象类可以有自己的成员变量,抽象类中的成员变量默认default、private、protected和public。可以再子类中重新定义、赋值。抽象类中的方法不能用private、static、synchronized、native修饰符。
-
说说反射的用途及实现
http://www.cnblogs.com/tartis/p/9299135.html
https://blog.csdn.net/maizi1045/article/details/53258551#commentBox
-
反射的概念:动态加载对象,并对对象进行剖析。在Java中的反射机制是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法,这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制
-
在Java中我们有三种方法可以获取一个对象的反射类:
-
通过getClass方法
在Java中,每一个
Object
都有一个getClass
方法,通过getClass方法我们可以获取到这个对象对应的反射类:String s = "ziwenxie"; Class<?> c = s.getClass();
-
通过forName方法
Class<?> c = Class.forName("java.lang.String");
-
使用.class
Class<?> c = String.class;
-
-
应用场合:在Java程序中许多对象在运行时都会出现两种类型:编译时类型和运行时类型
编译时的类型由声明该对象时使用的类型决定,运行时的类型由实际赋给对象的类型决定
如:Person p =new Student();
编译时类型为Person,而运行时为Student -
JAVA反射API
反射API用来生成在当前JAVA虚拟机中的类、接口或者对象的信息。
Class类:反射的核心类,可以获取类的属性,方法等内容信息。
Field类:Java.lang.reflect.表示类的属性,可以获取和设置类的中属性值。
Method类:Java.lang.reflect。表示类的方法,它可以用来获取类中方法的信息或者执行方法
Construcor类:Java.lang.reflect。表示类的构造方法。 -
应用:Struts2配置action,spring的bean注入
-
-
泛型与类型擦除
https://www.jianshu.com/p/4de08deb6ba4
- 泛型是JDK 1.5的一项新特性,它的本质是参数化类型(Parameterized Type)的应用,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口和泛型方法。
- Java语言中的泛型则不一样,它只在程序源码中存在,在编译后的字节码文件中,就已经被替换为原来的原生类型(Raw Type,也称为裸类型)了,并且在相应的地方插入了强制转型代码。
- 源程序:
public static void main(String[] args){ List <Integer> listInt=new ArrayList <Integer>(); List <String> listString=new ArrayList <String>(); Map<String, String> map = new HashMap<String, String>(); map.put("AAA", "BBB"); map.put("CCC", "DDD"); System.out.print(map.get("AAA")); }
-
编译后:
public static void main(String[] paramArrayOfString) { ArrayList localArrayList1 = new ArrayList(); ArrayList localArrayList2 = new ArrayList(); HashMap localHashMap = new HashMap(); localHashMap.put("AAA", "BBB"); localHashMap.put("CCC", "DDD"); System.out.print((String)localHashMap.get("AAA")); }
因此对于运行期的Java语言来说,
ArrayList <Integer>与ArrayList<String>
编译出来的代码是一样的,所以说泛型技术实际上是Java语言的一颗语法糖,Java语言中的泛型实现方法称为类型擦除,基于这种方法实现的泛型被称为伪泛型。 -
类型擦除:在jdk1.5之后,Java引进了泛型的概念,在不确定具体的类型,或者说想使用多种类型的时候,可以用泛型来表示,但是代码在具体执行的时候需要指定具体的类型,因此会在代码编译阶段,泛型会被具体的类型替换,这也就是类型擦除。举个简单的例子,Map<String,T> 这个map在写代码的时候可以不指定具体的类型,但是具体在执行的时候,需要确定类型的,如果不确定具体的类型,是没有办法确定value是哪一种类型的,而这个确定类型的动作就是在编译的时候确定的,也就是类型擦除。
-
说说自定义注解的场景及实现
-
HTTP请求的GET与POST方式的区别
- 使用GET方法时,查询字符串(键值对)被附加在URL地址后面一起发送到服务器,有以下特点:
- GET请求能够被缓存
- GET请求会保存在浏览器的浏览记录中
- 以GET请求的URL能够保存为浏览器书签
- GET请求有长度限制,最多只能1024字节
- GET请求主要用以获取数据
- 可能不是很安全,请求数据会暴露在url中
- 使用POST方法时,查询字符串在POST信息中单独存在,和HTTP请求一起发送到服务器,有以下特点:
- POST请求不能被缓存下来
- POST请求不会保存在浏览器浏览记录中
- 以POST请求的URL无法保存为浏览器书签
- POST请求没有长度限制
- 使用GET方法时,查询字符串(键值对)被附加在URL地址后面一起发送到服务器,有以下特点:
-
HTTP请求总共有哪几种类型
- 除了get和post,还有一下这几种:
- HEAD:与GET请求类似,不同在与服务器只返回HTTP头部信息,没有页面内容
- PUT:上传指定URL的描述
- DELETE:删除指定资源
- OPTIONS:返回服务器支持的HTTP方法
- CONNECT:转换为透明TCP/IP隧道的连接请求
-
常见的状态码
- 常见的状态码规则
-
返回的状态码和状态不一致的情况是有可能发生得
比如Web应用程序内部错误,但仍然返回 200 OK - 200 OK 请求正常处理完毕
- 204 No Content
请求成功处理,没有实体的主体返回 - 206 Partial Content
GET范围请求已成功处理 - 301 Moved Permanently
永久重定向,资源已永久分配新URI - 302 Found
临时重定向,资源已临时分配新URI - 303 See Other
临时重定向,期望使用GET定向获取 - 304 Not Modified
发送的附带条件请求未满足 - 307 Temporary Redirect
临时重定向,POST不会变成GET - 400 Bad Request
请求报文语法错误或参数错误 - 401 Unauthorized
需要通过HTTP认证,或认证失败 - 403 Forbidden
请求资源被拒绝 - 404 Not Found
无法找到请求资源(服务器无理由拒绝) - 500 Internal Server Error
服务器故障或Web应用故障 - 503 Service Unavailable
服务器超负载或停机维护
-
Session与Cookie区别
- 前言:HTTP是一种无状态的协议,为了分辨链接是谁发起的,需自己去解决这个问题。不然有些情况下即使是同一个网站每打开一个页面也都要登录一下。而Session和Cookie就是为解决这个问题而提出来的两个机制。
- session原理(有时间限制,默认30分钟,浏览器关闭即消失):
- 浏览器第一次访问服务器时会创建一个session对象并返回一个JSESSIONID=ID的值,创建一个Cookie对象key为JSSIONID,value为ID的值,将这个Cookie写回浏览器;
- 浏览器在第二次访问服务器的时候携带Cookie信息JSESSIONID(Java中)=ID的值,如果该JSESSIONID的session已经销毁,那么会重新创建一个新的session再返回一个新的JSESSIONID通过Cookie返回到浏览器;
- 针对一个web项目,一个浏览器是共享一个session,就算有两个web项目部署在同一个服务器上,针对两个项目的session是不同的。 如:你在tomcat上同时部署了两个web项目,分别是web1、web2。当你在一个浏览器上同时访问web1时创建的session是A1,访问web2时创建的session是A2。后面你再多次访问web1使用的session还是A1,多次访问web2时使用session就是A2
-
session是基于Cookie技术实现,重启浏览器后再次访问原有的连接依然会创建一个新的session,因为Cookie在关闭浏览器后就会消失,但是原来服务器的Session还在,只有等到了销毁的时间会自动销毁;
-
如果浏览器端禁用了Cookie,那么每次访问都会创建一个新的Session,但是我们可以通过服务器端程序重写URL即可,如果页面多连接多,会增加不必要的工作量,那可以强制让你用户开启接收Cookie后再让其访问即可。无法禁用服务器的session
-
两者区别:
- Cookie和Session都是会话技术,Cookie是运行在客户端,Session是运行在服务器端。
- Cookie有大小限制以及浏览器在存cookie的个数也有限制,Session是没有大小限制和服务器的内存大小有关。
- Cookie有安全隐患(因为存在客户端),通过拦截或本地文件找得到你的cookie后可以进行攻击。
- Session是保存在服务器端上会存在一段时间才会消失,如果session过多会增加服务器的压力。
- 存储数据量方面:session 能够存储任意的 java 对象,cookie 只能存储 String 类型的对象。
- Session过多时会消耗服务器资源,大型网站会有专门Session服务器,Cookie存在客户端没问题。
- 域的支持范围不一样,比方说a.com的Cookie在a.com下都能用,而www.a.com的Session在api.a.com下都不能用,解决这个问题的办法是JSONP或者跨域资源共享。
-
列出自己常用的JDK包
-
MVC设计思想
-
equals与==的区别
-
hashCode和equals方法的区别与联系
-
什么是Java序列化和反序列化,如何实现Java序列化?或者请解释Serializable 接口的作用
-
Object类中常见的方法,为什么wait notify会放在Object里边?
-
Java的平台无关性如何体现出来的
-
JDK和JRE的区别
-
Java 8有哪些新特性
参照:https://blog.csdn.net/why15732625998/article/details/79437930#commentBox