java基础知识总结 面试必考题
以下是java基础的精摘以及总结:
Object类中的方法
1.equals();
2.hashcode();
3.clone();
4.toString(),notify(),notifyAll(),wait();
5.finalize()
Java中实现序列化的两种方式
1.实现Serializable接口。
序列化的时候的一个关键字:transient(临时的)。它声明的变量实行序列化操作的时候不会写入到序列化文件中去。
2.实现Externalizable接口:
使用这个接口的场合是这样的:
一个类中我们只希望序列化一部分数据,其他数据都使用transient修饰的话显得有点麻烦,这时候我们使用externalizable接口,指定序列化的属性。
方法回调:
所谓回调,就是客户程序C调用服务程序S中的某个方法A,然后S又在某个时候反过来调用C中的某个方法B,对于C来说,这个B便叫做回调方法。
下面看一个实际例子来理解:
本示例设置一个提问者,一个回答者,而回答者需要回答提问者一个很深奥的问题时,这时需要很多时间去查找,提问者又开始做其他的事情,
等回答者找到答案后,再把答案告诉提问者。
java基本数据类型
1.整数类型
整数类型变量用来表示整数的数据类型。整数类型又分为字节型(byte)、短整型(short)、整型(int)、长整型(long)这四种。
2.浮点类型
浮点类型用来表示小数的数据类型。浮点类型分为float(单精度型)和double(双精度类型)这两种。float(单精度型)一般在精度要求不高的时候使用。double(双精度类型)一般在数值精度高的时候使用。
3.字符类型
字符类型的关键字是“char”。(在java中占2个字节)
4.布尔类型
布尔类型是表示逻辑值的基本数据类型。boolean常量有“真”和“假”这两个状态。一般用true表示“真”、false表示“假”。它的定义方法是在变量名前加上类型关键字boolean。
object对象的常用方法
(1)clone
保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常。
(2)equals
在Object中与==是一样的,子类一般需要重写该方法
(3)hashCode
该方法用于哈希查找,重写了equals方法一般都要重写hashCode方法。这个方法在一些具有哈希功能的Collection中用到。
(4)getClass
final方法,获得运行时类型
(5)wait
使当前线程等待该线程的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait()方法一直等待,直到获得锁或者被中断。wait(long timeout)设定一个超时间隔,如果规定时间内没有获得锁就返回。
(6)notify
唤醒在该对象上等待的某个线程
(7)notifyAll
唤醒在该对象上等待的所有线程
(8)toString
转换成字符串,一般子类都有重写,否则打印句柄。
几种级别Cache的大小
堆和栈的区别:
一.堆栈空间分配区别:
1.栈(操作系统):由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈;
2.堆(操作系统): 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。
二.堆栈缓存方式区别:
1.栈使用的是一级缓存, 他们通常都是被调用时处于存储空间中,调用完毕立即释放;
2.堆是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收)。所以调用这些对象的速度要相对来得低一些。
三.堆栈数据结构区别:
堆(数据结构):堆可以被看成是一棵树,如:堆排序;
栈(数据结构):一种先进后出的数据结构。
fork的返回值
父进程fork()之后返回值为子进程的pid号,而子进程fork()之后的返回值为0。
过fork()系统调用我们可以创建一个和当前进程印象一样的新进程.我们通常将新进程称为子进程,而当前进程称为父进程.而子进程继承了父进程的整个地址空间,其中包括了进程上下文,堆栈地址,内存信息进程控制块(PCB)等.
1.父子进程
那么我们首先来先说说父进程和子进程之间的区别:
-
父进程设置了锁,子进程不继承
-
进程ID不同
-
子进程的未决告警被清除
-
子进程的未决信号集设置为空集
2.fork系统调用说明
通过man手册我们可以轻松知道fork()包含的头文件<sys/types.h>和<unistd.h>,功能就是创建一个子进程.函数原型:pid_t fork(void),pid_t是带一个代表经常号pid的数据结构.如果创建成功一个子进程,对于父进程来说是返回子进程的ID.而对于子进程来说就是返回0.而返回-1代表创建子进程失败.
MD5与AES加密
MD5:
MD5全称为信息-摘要算法(哈希算法),是为计算机安全领域的散列函数,用于确保消息的完整性。另外摘要算法还有SHA1,具体请度娘。
MD5是一种单向加密,它的加密不可逆,它将任意长度的字符串,经过算法计算后生成固定长度的数据,一般为16位表示。
MD5的用途:
1. 消息完整性:每份数据生成的MD5码不同,所以可以吧MD5码和数据一块发送,在对端使用MD5加密对数据加密在与接收的MD5码做对比,保证数据的正确性。
2. 安全访问认证:常被用到 mysql和传递用户账户信息和密码,从用户端发送到服务器的只是一段128位的摘要,服务器拿到后直接将其存入数据库,下次登录只需与服务器的密文进行对比即可,这样保护了用户的信息,即便是后台人员也无法去获取用户的账户密码。
3. 数字签名
AES加密是一种分组加密,他将明文划分一组一组的,每组明文长度相等,一次加密一组明文,直到全部加密,分组长度为128位(16字节),明文长度不足的进行填充。AES加密是字节加密,使用时要转成字节码。明文分组用字节单位的正方形矩阵表示,一般称为状态矩阵。
1、Integer默认值是null,而int默认值是0;
2、声明为Integer的变量需要实例化,而声明为int的变量不需要实例化;
3、Integer是对象,用一个引用指向这个对象;而int是基本类型,直接存储数值。
Java两种数据类型分类:
原始数据类型,分为boolean、byte、in、char、long、short、double、float 。
引用数据类型 ,分为数组类、接口。
为了编程的方便还是引入了基本数据类型,但是为了能够将这些基本数据类型当成对象操作,Java为每 一个基本数据类型都引入了对应的包装类型,int的包装类就是Integer,从Java 5开始引入了自动装箱/拆箱机制,使得二者可以相互转换。
Int是将一个数值向下取整为最接近的整数的函数。INT是数据库中常用函数中的取整函数,常用来判别一个数能否被另一个数整除。
匿名内部类是否可以继承类?是否可以实现接口?
匿名内部类在实现时必须借助一个类或一个接口,若从这个层次上讲它是可以继承其他类也可以实现接口的,
但若是通过extends 或implements 关键字那是不可能的.
可以继承其他类,但不能用extends。
可以实现某接口,但不能用implements。
Java语言的参数传递(传值方式?)
Java语言的参数传递分为两种
1、按值传递(by value)(值传递)
适用范围:8种基本数据类型、 String对象
特点:在内存中复制一份数据,把复制后的数据传递到方法内部
作用:在方法内部改变参数的值,外部数据不会跟着发生改变
2、按址传递(by address)(引用传递)
适用范围:数组、除String以外的其他所有类型的对象
特点:将对象的地址传递到方法内部
作用:在方法内部修改对象的内容,外部数据也会跟着发生改变
(ps:例如int是按值传递的,而Integer是按址传递的;double是按值传递的,而Double是按址传递的)
java变量存储的位置
1.寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制.
2. 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池中。)
3. 堆:存放所有new出来的对象。
4. 静态域:存放静态成员(static定义的)
5. 常量池:存放字符串常量和基本类型常量(public static final)。
6. 非RAM存储:硬盘等永久存储空间
jdk1.7和1.8的区别
JDK1.8的新特性:
内部类有什么作用?
内部类可以有多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立.在单个外围类当中,可以让多个内部类以不同的方式实现同一接口,或者继承同一个类.创建内部类对象的时刻不依赖于外部类对象的创建.内部类并没有令人疑惑的”is-a”关系,它就像是一个独立的实体.此外,内部类提供了更好的封装,除了该外围类,其他类都不能访问.
深拷贝和浅拷贝的区别是什么?
浅拷贝:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象.
深拷贝:被复制对象的所有变量都含有与原来的对象相同的值.而那些引用其他对象的变量将指向被复制过的新对象.而不再是原有的那些被引用的对象.换言之.深拷贝把要复制的对象所引用的对象都复制了一遍.
String s = new String("abc")创建了几个String对象?
2个.一个是字符串字面常数,在字符串常量池中;另一个是new出来的字符串对象,在堆中.
其位置在方法区上面的驻留字符串(Interned Strings)的位置,之前一直把它和运行时常量池搞混,其实是两个完全不同的存储区域,字符串常量池是全局共享的。
Comparator和Comparable的区别?
Comparable接口用于定义对象的自然顺序,而 comparator 通常用于定义用户定制的顺序.Comparable 总是只有一个,但是可以有多个 comparator 来定义对象的顺序.
如何实现集合排序?
你=可以使用有序集合,如TreeSet 或TreeMap,也可以使用有顺序的的集合,如 list,然后通过Collections.sort() 来排序.
Java 中Serializable 与 Externalizable 的区别
Serializable 接口是一个序列化Java 类的接口,以便于它们可以在网络上传输或者可以将它们的状态保存在磁盘上,是 JVM 内嵌的默认序列化方式,成本高,脆弱而且不安全.
Externalizable 允许你控制整个序列化过程,指定特定的二进制格式,增加安全机制.
JDK 1.8特性
JDK 1.8在 Java 历史上是一个开创新的版本,其中有5个主要的特性:
-
Lambda 表达式: 允许像对象一样传递匿名函数
-
Stream API: 充分利用现代多核 CPU,可以写出很简洁的代码
-
Date 与 Time API: 提供了一个稳定,简单的日期和时间库可供你使用
-
扩展方法: 现在接口中可以有静态,默认方法。
-
重复注解: 现在你可以将相同的注解在同一类型上使用多次
JDK 1.9特性
-
引入了模块化机制.
-
加入JShell.可以控制台启动 jshell ,并直接启动输入和执行Java 代码.
-
添加了一些集合类的工厂方法,比如现在可以Set.of(1,2)来直接创建Set对象.
-
更好用的Stream API.
-
接口中支持私有方法了
为什么有了int还会有Integer
Java 为每个原始类型提供了包装类型:
- 原始类型: boolean,char,byte,short,int,long,float,double
- 包装类型:Boolean,Character,Byte,Short,Integer,Long,Float,Double
java就是面向对象语言,
至于为什么保留int,因为性能,
Integer 也是Object , 也要垃圾回收,
基本类型不需要垃圾回收。
比如int a= 5;Integer b=5;对于a你只能用来做计算,比如加减乘除,对于b你可以用来做很多事情,因为他是一个对象,他有很多方法,你可以像使用String对象那样使用它。
或者当需要往ArrayList,HashMap中放东西时,像int,double这种内建类型是放不进去的,因为容器都是装object对象的,这是就需要这些内建类型的外覆类了。
两者区别:
1、Integer是int的包装类,int则是java的一种基本数据类型
2、Integer变量必须实例化后才能使用,而int变量不需要
3、Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象;而int则是直接存储数据值
4、Integer的默认值是null,int的默认值是0
int:属于基本类型,不存在“引用”这个概念;其数据是存储在栈空间中;
Integer:属于继承自Object的类,是按照java存储对象的内存模型来存储的;引用存储在栈中,对象数据存储在堆中;
栈中存的是基本数据类型和堆中对象的引用
有return的情况下try catch finally的执行顺序
https://www.cnblogs.com/fery/p/4709841.html
1、不管有没有出现异常,finally块中代码都会执行;
2、当try和catch中有return时,finally仍然会执行;
3、finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,不管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是在finally执行前确定的;
4、finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。
最终结论:任何执行try 或者catch中的return语句之前,都会先执行finally语句,如果finally存在的话。
如果finally中有return语句,那么程序就return了,所以finally中的return是一定会被return的,
编译器把finally中的return实现为一个warning。
num++;num+=1;num = num +1;哪个效率最高
a++:a先创建自身的一个副本,然后a自增1,最后返回副本的值
a+=1: 事实上相当于++a
a=a+1: 虽然有点雷同于a+=1,但不同的是此时右值的a和1做相加操作,形成一个副本然后赋值给a,所以有额外操作
++a:将a自增1并返回a
i++ :先引用后增加
++i :先增加后引用
i = i+1 i +=1 i++ 哪个效率更高?为什么?
分析:
第一个:i = i+1 效率最低
步骤:1. 读取右i的地址
2. i+1
3. 读取左i的地址
4.将右值传给左i(编译器并不认为左右i的地址相同)。
第二个: i += 1 效率其次
步骤:1. 读取右i的地址
2. i+1
3. 将得到的值传给i(因为i的地址已经的读出)。
第三个: i ++ 效率最高
步骤:1. 读取右i的地址
2. i自增1
String str=new String(“abc”);创建了几个对象
2个
String a=“ab”+“cd”;
“ab”和“cd”分别创建了一个对象,它们经过“+”连接后又创建了一个对象“abcd”,因此一共三个,并且它们都被保存在字符串池里了
String str1 = new String("A"+"B") ; 会创建多少个对象?
String str2 = new String("ABC") + "ABC" ; 会创建多少个对象?
str1:
字符串常量池:"A","B","AB" : 3个
堆:new String("AB") :1个
引用: str1 :1个
总共 : 5个
str2 :
字符串常量池:"ABC" : 1个
堆:new String("ABC") :1个
引用: str2 :1个
总共 : 3个
a=a+b和a+=b的区别
-
a+=b;执行的时候效率高。
-
+=运算中,结合了强制类型转换的功能
3*0.1==0.3将会返回什么?true还是false?
fale,因为浮点数不能完全精确的表示出来,一般会损失精度。
static关键字
方便在没有创建对象的情况下来进行调用(方法/变量)。
很显然,被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。
-
static可以用来修饰类的成员方法、类的成员变量
-
static是不允许用来修饰局部变量。
java虚拟机怎么识别是符合标准的class文件,魔数
每个Class文件的头4个字节被称为魔数,它的唯一作用是用于确定这个文件是否为一个能被java虚拟机所接收的Class类文件,即用于判定文件是否是符合规范的java Class文件。虽然说后缀名“.class”可以表明文件是一个Class文件,但是文件后缀名是可以随意被改动的,基于安全的考虑,很多文件都通过魔数值来唯一确定文件类型,java的Class文件魔数是:0xCAFEBABE.
栈中需要压入哪些数据。
方法参数,返回值,以及返回地址。
java四种修饰符的限制范围
区别:
(1)public:可以被所有其他类所访问。
(2)private:只能被自己访问和修改。
(3)protected:自身,子类及同一个包中类可以访问。
(4)default(默认):同一包中的类可以访问
final是线程安全的吗?
首先被final关键字修饰的属性,是不可修改的。如果final修饰一个引用,那么其实被修饰的这个东西也可能是不安全的,因为可能被引用的这个类自己本身也是线程不安全的。
那么线程安全该怎么理解?
线程安全就是多线程并发访问一个数据的时候,对这个数据进行保护,同一时间只允许一个线程访问这个数据。final很明显并没有对此有什么限制。
根据以上可以得出啥结论呢,final修饰的对象本身安全,因为没办法再次更改他的指向了,也就不存在并发写入一个数据的问题了。但是类似于Collection这类可以改变自己元素值得对象来说,还是不安全的。
僵尸进程的处理
1.利用top命令,效果如下,上文中创建的僵尸进程
也可以ps -aux |grep Z 来查看僵尸进程 ,僵尸进程的状态显示的是Z
2.杀死僵尸进程
从僵尸进程的概念可以看出,父进程没有结束导致的,我们把父进程杀死,父进程就会寻找他自己创建的子进程,从而杀死僵尸进程。所以我们要杀死父进程就可以。所以第一步要找到父进程 ps -ef | grep defunct_process_pid(僵尸进程pid) 然后执行,kill -s 9 父进程的pid。演示如下:
然后杀死 kill -s 9 11781
序列化的几种方式
第一种:使用默认的序列化机制,即实现Serializable接口即可,不需要实现任何方法。
第二种:实现Externalizable接口。
Externalizable接口是继承自Serializable接口的,我们在实现Externalizable接口时,必须实现writeExternal(ObjectOutput)和readExternal(ObjectInput)方法,在这两个方法下我们可以手动的进行序列化和反序列化那些需要保存的成员变量。
有时我们不希望序列化那么多,可以使用这个接口,这个接口的writeExternal()和readExternal()方法可以指定序列化哪些属性。
G1:是一款面向服务端应用的垃圾收集器
特点:
1、并行于并发:G1能充分利用CPU、多核环境下的硬件优势,使用多个CPU(CPU或者CPU核心)来缩短stop-The-World停顿时间。部分其他收集器原本需要停顿Java线程执行的GC动作,G1收集器仍然可以通过并发的方式让java程序继续执行。
2、分代收集:分代概念在G1中依然得以保留。虽然G1可以不需要其它收集器配合就能独立管理整个GC堆,但它能够采用不同的方式去处理新创建的对象和已经存活了一段时间、熬过多次GC的旧对象以获取更好的收集效果。也就是说G1可以自己管理新生代和老年代了。
3、空间整合:由于G1使用了独立区域(Region)概念,G1从整体来看是基于“标记-整理”算法实现收集,从局部(两个Region)上来看是基于“复制”算法实现的,但无论如何,这两种算法都意味着G1运作期间不会产生内存空间碎片。
4、可预测的停顿:这是G1相对于CMS的另一大优势,降低停顿时间是G1和CMS共同的关注点,但G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用这明确指定一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒。
static关键字的
基本作用,简而言之,一句话来描述就是:
方便在没有创建对象的情况下来进行调用(方法/变量)。
注意:
-
Java中的static关键字不会影响到变量或者方法的作用域。在Java中能够影响到访问权限的只有private、public、protected(包括包访问权限)这几个关键字。
-
static是不允许用来修饰局部变量
多态
多态概念:父类的引用可以指向子类的对象,且可以调用子类中覆盖父类的方法,但不可以调用子类特有的方法,多态屏蔽了子类之间的差异,提高了代码的复用性。
多态分为编译时多态与运行时多态:
编译时多态:实现是重载,重载是方法的参数表不同,方法名相同,在不同对象调用方法的时候需要调用相对应的方法,但是这不是多态的全部,这样写代码也比较臃肿,没有复用性。静态绑定。
public class Test {
public static void main(String[] args) {
Person p = new Person(); //对象引用本类实例
Man m = new Man(); //编译时多态,执行Person类的toString()
System.out.println(p.toString());
System.out.println(m.toString()); //编译时多态,执行Man类的toString()
}
}
class Person{
public String toString() {
String name = "Person";
return name;
}
}
class Man extends Person{
public String toString(){
String name = "Man";
return name;
}
}
运行时多态:运行时多态体现了多态的全部,子类继承父类之后,多态就可以用到参数上,这样在不同对象掉用方法时,即可实现不同的输出。动态绑定,父类即可根据对象的不同调用不同的方法达到不同的实现。
程序运行时,Java从实例所属的类(new 类)开始寻找匹配的方法执行,如果当前类中没有匹配的方法,则沿着继承关系逐层向上,依次在父类或各祖先类中寻找匹配方法,直到Object类。寻找p.toString()匹配执行方法的过程如下图所示。
方法重写与方法重载的区别
方法重载:Overload
作用:解决了同一个类中,相同功能的方法名不同的问题
既然是相同的功能,那么方法名就应该相同
规则:两同一不同
同类中,方法名相同,方法参数列表不同(参数类型,参数个数,参数顺序)
例如:
public class TestClass{
方法A:
public int add (int a,int b){
return a+b;
}
方法B:
public int add (float a){
return a+b;
}
}
方法重写:Override
作用:解决了子类继承父类之后,可能父类的某一个方法不满足子类的具体特征,此时需要重新在子类定义该方法的方法体
规则:一同两小一大
i++和++i效率对比
前置比后置效率高 ,后置需要构造临时对象并返回。
视频直播用到了哪些传送协议
RTP :(Real-time Transport Protocol)实时传输协议
RTP协议是针对多媒体数据流的一种传输层协议。RTP是建立在UDP协议上的
RTCP: (Real-time Transport Control Protocol)实时传输控制协议
RTSP:(Real Time Streaming Protocol)实时流协议
TCP的最大包长
用wireshark捕包。 为什么frame那一行是1514bytes?
以太网封装IP数据包的最大长度是1500字节,也就是说以太网最大帧长应该是以太网首部加上1500,再加上7字节的前导同步码和1字节的帧开始定界符,具体就是:7字节前导同步吗+1字节帧开始定界符+6字节的目的MAC+6字节的源MAC+2字节的帧类型+1500+4字节的CRC校验。
按照上述,最大帧应该是1526字节,但是实际上我们抓包得到的最大帧是1514字节,为什么不是1526字节呢?原因是当数据帧到达网卡时,在物理层上网卡要先去掉前导同步码和帧开始定界符,然后对帧进行CRC检验,如果帧校验和错,就丢弃此帧。如果校验和正确,就判断帧的目的硬件地址是否符合自己的接收条件(目的地址是自己的物理硬件地址、广播地址、可接收的多播硬件地址等),如果符合,就将帧交“设备驱动程序”做进一步处理。这时我们的抓包软件才能抓到数据,因此,抓包软件抓到的是去掉前导同步码、帧开始分界符、CRC校验之外的数据,其最大值是6+6+2+1500=1514。
为什么Integer a=100,b=100时候a==b返回true,而Integer c=1000,d=1000时候c==d返回false
我们知道,如果两个引用指向相同的对象,通过==比较,他们是相等的;如果两个引用指向不同的对象,通过==比较,它们不是相等的,即使它们存储着相同的内容。
如果值是在-128至127之间,它将从缓存中获取实例并返回,它们之间的内存地址是相同的。
Java中为什么没有多继承
假设A类和B类都有t方法,且具体实现不一样。
C类继承A类和B类,当C类调用t方法时,会出现歧义。
因为,A类和B类都有t方法,但具体实现不一样。
可以多实现是因为,接口中的方法没有具体实现。
继承多个接口,就算两个接口中有相同的方法,也不会出现矛盾。
++num和num++哪个执行速度更
num++在执行过程中是需要经历两个过程的,首先是将num读到寄存器,再将num对应的内存地址的值进行加一操作,调用的时候是使用的是寄存器中的值,而不是直接用地址中的值。
++num在执行的时候是直接对num所对应的内存地址进行加一操作,调用的时候是直接使用该内存地址中的值进行操作。
所以在使用++num时速度会相对来说要快那么一点点。
字符串的拼接方法
1.直接用“+”号
2.使用String的方法concat
3.使用StringBuilder的append
4.使用StringBuffer的append
这几种方式性能的从低到高进行排序,则顺序为:“+”< concat ( ) < StringBuffer < StringBuilder
一个十进制的数在内存中是怎么存的?
二进制补码形式储存的,二进制补码因为整形数据在内存中是以2进制本数的补码存在的;但正整数的补码还是原来的2进制,而负数则要先取反再+1才是它的补码
Java中交互方式分为同步和异步
同步交互:指发送一个请求,需要等待返回,然后才能够发送下一个请求,有个等待过程;
异步交互:指发送一个请求,不需要等待返回,随时可以再发送下一个请求,即不需要等待。
区别:一个需要等待,一个不需要等待,在部分情况下,我们的项目开发中都会优先选择不需要等待的异步交互方式。
哪些情况建议使用同步交互呢?比如银行的转账系统,对数据库的保存操作等等,都会使用同步交互操作,其余情况都优先使用异步交互。
请你解释为什么会出现4.0-3.6=0.40000001这种现象?
原因简单来说是这样:2进制的小数无法精确的表达10进制小数,计算机在计算10进制小数的过程中要先转换为2进制进行计算,这个过程中出现了误差。
String转Long类型的方法
Long.ValueOf("String")与Long.parseLong("String")的区别
-
Long.ValueOf("String")返回Long包装类型
-
Long.parseLong("String")返回long基本数据类型
ArrayList的remove操作
ArrayList有俩个remove()重载方法,一个参数是int类型,另一个参数是Object类型,remove(1)是删除索引为1的元素,remove(new Integer(1))是删除元素1,底层是用equals进行比较的。
&和&&的区别
&&:短路逻辑与,当&&两边的表达式结果都为true时整体才为true,并且有短路的作用即当第一个表达式结果为false时第二个表达式将不再执行。
&:逻辑与或者位运算符,当&作为逻辑与时和&&的作用一样但是没有短路的作用即当第一个表达式为false时第二个表达式也会运算,但对整体结果没有影响,当&的两边为整数 时,&作为位运算符存在,计算方式:将两个整数转换为二进制数,再取两个整数的最低4位进行运算,当二进制数都为1时计算结果才为1,否则都为0。
java中是否可以覆盖一个private方法?
在学习继承的过程中,我们知道,如果在父类中修饰了一个private的方法,子类继承之后,对子类也是不可见的。那么如果子类声明了一个跟父类中定义为private一样的方法,那么编译器只当作是你子类自己新增的方法,并不能算是继承过来的。
是否可以覆盖一个static方法?
覆盖又称为重写,重写就是子类中的方法和子类继承的父类中的方法一样(函数名、参数类型、参数、返回值类型),但子类的访问权限不要低于父类的访问权限。重写的前提是必须要继承,private修饰不支持继承,因此被私有的方法不能重写。静态的方法形式上是可以被重写的,即子类中可以重写父类中的静态方法,但实际上在内存的角度上静态方法是不可以被重写的。
Java中static方法不能被覆盖,因为方法覆盖是基于运行时动态绑定的,而static方法是编译时静态绑定的。static方法跟类的任何实例都不相关,所以概念上不适用。
什么是泛型
泛型就是类型参数化,处理的数据类型不是固定的,而是可以作为参数传入。
是否可以在static环境中访问非static变量?
因为静态的成员属于类,随着类的加载而加载到静态方法区内存,当类加载时,此时不一定有实例创建,没有实例,就不可以访问非静态的成员(而非静态变量是属于实例的,要在new一个实例之后,值才会存在。)。
请解释一下extends 和super 泛型限定符
extends 指定上界限,只能传入本类和子类
super 指定下界限,只能传入本类和父类
<? extends T>限定参数类型的上界:参数类型必须是T或T的子类型
<? super T> 限定参数类型的下界:参数类型必须是T或T的超类型
Comparable和Comparator区别比较
-
Comparable是排序接口,若一个类实现了Comparable接口,就意味着“该类支持排序”。实现了Comparable接口的类的对象的列表或数组可以通过Collections.sort或Arrays.sort进行自动排序。
-
Comparator是比较器,我们若需要控制某个类的次序,可以建立一个“该类的比较器”来进行排序。
-
Comparable相当于“内部比较器”,而Comparator相当于“外部比较器”。
public int compareTo(T o);
1、比较者大于被比较者(也就是compareTo方法里面的对象),那么返回正整数
2、比较者等于被比较者,那么返回0
3、比较者小于被比较者,那么返回负整数
int compare(T o1, T o2);
1、o1大于o2,返回正整数
2、o1等于o2,返回0
3、o1小于o3,返回负整数
两种方法各有优劣, 用Comparable 简单, 只要实现Comparable 接口的对象直接就成为一个可以比较的对象,但是需要修改源代码。 用Comparator 的好处是不需要修改源代码, 而是另外实现一个比较器, 当某个自定义的对象需要作比较的时候,把比较器和对象一起传递过去就可以比大小了, 并且在Comparator 里面用户可以自己实现复杂的可以通用的逻辑,使其可以匹配一些比较简单的对象,那样就可以节省很多重复劳动了。
Overload和Override的区别。Overload的方法是否可以改变返回值的类型?
Overload重载:
同一个类中,方法名相同,参数列表不同。与返回值类型无关。
Override重写:
存在于子父类,或者子父接口中,方法声明相同。
Overload的方法可以改变返回值的类型,因为它与返回值类型无关。
Static Nested Class(嵌套类) 和 Inner Class(内部类)的不同
nested-class和inner-class都是外层类的成员变量。只不过一个是静态的,一个是非静态的。
因此,nested-class和inner-class都可以被声明为private,public,protested或package private (这里回忆一下,普通的class在声明时只能是public或package private的)。
但是有静态和非静态的不同可知:nested-class是和类相关的,而inner-class是和实例相关的。因此可以不实例化对象,就直接访问nested-class,而必须实例化类才能访问inner-class。而nested-class不能访问外层类的其他成员变量或方法,而inner-class则可以。
这里还有一个有意思的事:因为inner-class是非静态成员变量,因此inner-class中不能再定义静态变量或方法了。
JVM加载class文件的原理机制?
当Java程序需要使用某个类时,JVM会确保这个类已经被加载、连接(验证、准备和解析)和初始化。类的加载是指把类的.class文件中的数据读入到内存中,通常是创建一个字节数组读入.class文件,然后产生与所加载类对应的Class对象。加载完成后,Class对象还不完整,所以此时的类还不可用。当类被加载后就进入连接阶段,这一阶段包括验证、准备(为静态变量分配内存并设置默认的初始值)和解析(将符号引用替换为直接引用)三个步骤。最后JVM对类进行初始化,包括:1)如果类存在直接的父类并且这个类还没有被初始化,那么就先初始化父类;2)如果类中存在初始化语句,就依次执行这些初始化语句。
为啥final类型的map或者arraylist可以修改数据 而final类型的String变量不可以修改数据呢
对List或map的add或put操作,没有修改引用。而对字符串的修改,是整个引用都要指向一个不同的字符串了。
重温一下final
修饰类:当用final修饰一个类时,表明这个类不能被继承。
修饰方法 :
final修饰的方法不能被重写(可以重载多个final修饰的方法)。此处需要注意的一点是:
因为重写的前提是子类可以从父类中继承此方法,如果父类中final修饰的方法同时,访问控制权限为private,将会导致子类中不能直接继承到此方法,因此,此时可以在子类中定义相同的方法名和参数,此时不再产生重写与final的矛盾,而是在子类中重新定义了新的方法。(注:类的private方法会隐式地被指定为final方法。)
修饰变量:
final成员变量表示常量,只能被赋值一次,赋值后值不再改变。
final修饰的引用变量:
被final修饰的引用变量一旦初始化赋值之后就不能再指向其他的对象
关于多态
什么是多态?
概念:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。简单的说:父类的引用指向子类型的对象
为什么要用多态呢?
原因:我们知道,封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——1.代码重用。而多态除了代码的复用性外,还可以解决项目中紧偶合的问题,提高程序的可扩展性.。耦合度讲的是模块模块之间,代码代码之间的关联度,通过对系统的分析把他分解成一个一个子模块,子模块提供稳定的接口,达到降2.低系统耦合度的的目的,模块模块之间尽量使用模块接口访问,而不是随意引用其他模块的成员变量。
多态有什么好处?
有两个好处:
1. 应用程序不必为每一个派生类编写功能调用,只需要对抽象基类进行处理即可。大大提高程序的可复用性。//继承
2. 派生类的功能可以被基类的方法或引用变量所调用,这叫向后兼容,可以提高可扩充性和可维护性。 //多态的真