1、java为什么能跨平台运行
java语言是先编译后运行,把java文件编译成.class文件,然后不同的硬件平台上安装有不同的Java虚拟机(JVM),由JVM来把字节码再“翻译”成所对应的硬件平台能够执行的代码。因此对于Java编程者来说,不需要考虑硬件平台是什么。所以Java可以跨平台。
2、java的基本类型和对应的封装类
基本数据类型分为8种:基本类型:byte 二进制位数:8
包装类:java.lang.Byte
最小值:Byte.MIN_VALUE=-128
最大值:Byte.MAX_VALUE=127
基本类型:short 二进制位数:16
包装类:java.lang.Short
最小值:Short.MIN_VALUE=-32768
最大值:Short.MAX_VALUE=32767
基本类型:int 二进制位数:32
包装类:java.lang.Integer
最小值:Integer.MIN_VALUE=-2147483648
最大值:Integer.MAX_VALUE=2147483647
基本类型:long 二进制位数:64
包装类:java.lang.Long
最小值:Long.MIN_VALUE=-9223372036854775808
最大值:Long.MAX_VALUE=9223372036854775807
基本类型:float 二进制位数:32
包装类:java.lang.Float
最小值:Float.MIN_VALUE=1.4E-45
最大值:Float.MAX_VALUE=3.4028235E38
基本类型:double 二进制位数:64
包装类:java.lang.Double
最小值:Double.MIN_VALUE=4.9E-324
最大值:Double.MAX_VALUE=1.7976931348623157E308
基本类型:char 二进制位数:16
包装类:java.lang.Character
最小值:Character.MIN_VALUE=0
最大值:Character.MAX_VALUE=65535
基本类型:boolean 在不同的平台占的字节数不同
包装类:java.lang.Boolean
double的取值范围比long大。
byte,char,short 的混合运算结果是int类型的(原因是结果可能产生溢出)
表达式中的结果由等级最高的类型决定。
默认转换 从低到高
强制转换 从高到低(有可能产生溢出)
3、jvm类的加载过程
1. 类的加载2. 类的连接
1验证 验证被加载后的类是否有正确的结构,类数据是否会符合虚拟机的要求,确保不会危害虚拟机安全。
2准备 为类的静态变量(static filed)在方法区分配内存,并赋默认初值(0值或null值)。如static int a = 100;
3 解析 将类的二进制数据中的符号引用换为直接引用
3. 类的初始化
4、垃圾回收
当一个对象没有被任何引用的时候,系统就会释放他所占的内存空间。
5、fianl finally finalize 区别
1、final
final可以用于成员变量(包括方法参数),方法、类。
final成员
作为变量
变量一旦被初始化便不可改变(对于基本类型,指的是值不变;对于对象类型,指的是引用不变),初始化只可能在两个地方:定义处和构造函数。
作为方法参数
对于基本类型,定义成final参数没有什么意义,因为基本类型就是传值,不会影响调用语句中的变量;对于对象类型,在方法中如果参数确认不需要改变时,定义成final参数可以防止方法中无意的修改而影响到调用方法。
final方法
不可覆写
编译器将对此方法的调用转化成行内(inline)调用,即直接把方法主体插入到调用处(方法主体内容过多的时候反而会影响效率)
final类
不可继承
2、finally
异常处理关键字,finally中的主体总会执行,不管异常发生是否。
return语句并不是函数的最终出口,如果有finally语句,这在return之后还会执行finally(return的值会暂存在栈里面,等待finally执行后再返回)
简单地总结如下:
try语句在返回前,将其他所有的操作执行完,保留好要返回的值,而后转入执行finally中的语句,而后分为以下三种情况:
情况一:如果finally中有return语句,则会将try中的return语句”覆盖“掉,直接执行finally中的return语句,得到返回值,这样便无法得到try之前保留好的返回值。
情况二:如果finally中没有return语句,也没有改变要返回值,则执行完finally中的语句后,会接着执行try中的return语句,返回之前保留的值。
情况三:如果finally中没有return语句,但是改变了要返回的值,这里有点类似与引用传递和值传递的区别,分以下两种情况,:
如果return的数据是基本数据类型,则在finally中对该基本数据的改变不起作用,try中的return语句依然会返回进入finally块之前保留的值。
如果return的数据是引用数据类型,而在finally中对该引用数据类型的属性值的改变起作用,try中的return语句返回的就是在finally中改变后的该属性的值
3、finalize
类的finalize方法,可以告诉垃圾回收器应该执行的操作,该方法从Object类继承而来。在从堆中永久删除对象之前,垃圾回收器调用该对象的finalize方法。注意,无法确切地保证垃圾回收器何时调用该方法,也无法保证调用不同对象的方法的顺序。即使一个对象包含另一个对象的引用,或者在释放一个对象很久以前就释放了另一个对象,也可能会以任意的顺序调用这两个对象的finalize方法。如果必须保证采用特定的顺序,则必须提供自己的特有清理方法
6、java里的四种引用关系
1、强引用:一个对象赋给一个引用就是强引用,比如new一个对象,一个对象被赋值一个对象。2、软引用:用SoftReference类实现,一般不会轻易回收,只有内存不够才会回收。
3、弱引用:用WeekReference类实现,一旦垃圾回收已启动,就会回收。
4、虚引用:不能单独存在,必须和引用队列联合使用。主要作用是跟踪对象被回收的状态。
7、break,continue,return 的区别 和各自的作用
1)break 直接跳出当前的循环,从当前循环外面开始执行,忽略循环体中任何其他语句和循环条件测试。他只能跳出一层循环,如果你的循环是嵌套循环,那么你需要按照你嵌套的层次,逐步使用break来跳出.
2)continue 终止本循环体内的当前循环,继续执行下一次循环,并且continue下面的代码不会执行。
3)return 是结束整个方法,或者是结束方法并且返回方法得到的值。
补充:goto是java中的保留关键字,用continue,break 和 位置标签可以实现goto 的功能但是不推荐使用
8、for(,,),while(true)死循环那个效率更高
for (;;)指令少,不占用寄存器,而且没有判断跳转,比while (1)好。
9、形参 和 实参
1)形参称为形式参数,形参是在定义方法的时候产生的,只在整个方法内有效,在方法外部无效。
2)实参是实际参数,它具有实际的值,是主调函数传递给被调用方法的值。
功能
实参和形参的功能是用作数据传送,当发生函数调用时,主调函数将实参传递给被调函数的形参,从而实现主调函数向被调函数的值传递。
区别
1)形参变量只有在被调用是才会分配内存空间,当调用结束后,就会立即释放所分配的内存单元。因此,形参变量只有在方法内部有效。
2)实参可以是常量,变量,表达式,函数等,无论是什么的类型,在进行函数调用时,他们必须具有确定的值。
3)实参和形参在个数,类型,顺序必须保持一致。
10、java的传值方式
1)值传递,方法调用时,实际参数把他的值传递给对应的形参,实参传递给形参的值是实参值的copy,形参值的改变不会影响实参的值。
值传递包括八种基本基本类型和String类型。
2)引用传递 也称为地址传值,方法调用时,实际参数引用(地址)传递给形参,在方法执行中,对形式参数的操作实际上就是对实际参数的操作,方法执行中形式参数值的改变将会影响实际参数的值。
引用传递包括 类的实例,数组,接口等。
11、方法的重载,重载的条件
定义:在一个类中,方法名相同,方法的参数列表不相同称为方法的重载。重载是一个类中多态性的一种表现。
重载的条件
参数的类型不同,参数的顺序不同,参数的个数不同可以构成方法的重载。
12 、方法重写,重写的条件
定义:父类与子类之间的多态性,对父类的函数进行重新定义。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。
当子类中重写了父类的方法,子类的中方法就覆盖了父类的方法,如果要调用父类的方法,就必须使用super关键字。
重写的条件
1、重写方法不能比被重写方法限制有更严格的访问级别。(重写的方法需要比被重写的方法的修饰符的权限高)
2、参数列表必须与被重写的方法保持一致。
3、返回值类型必须与被重写的方法一致。
4.重写方法不能抛出新的异常或者比被重写方法声明的检查异常更广的检查异常。但是可以抛出更少,更有限或者不抛出异常。
5、不能重写被标识为final的方法。
6、如果一个方法不能被继承,则不能重写它。(被private修饰的)
重写 要求两同两小一大原则, 方法名相同,参数类型相同,子类返回类型小于等于父类方法返回类型, 子类抛出异常小于等于父类方法抛出异常, 子类访问权限大于等于父类方法访问权限。[注意:这里的返回类型必须要在有继承关系的前提下比较]
13、方法重写和重载的区别
方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被“屏蔽”了,而且如果子类的方法名和参数类型和个数都和父类相同,那么子类的返回值类型必须和父类的相同;如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载。Overloaded的方法,是可以改变返回值的类型。也就是说,重载的返回值类型可以相同也可以不同。
14、动态参数列表
在jdk1.5以后,有新的写法 ,动态参数列表
参数类型固定 参数的个数可以是动态的 0-n
使用起来类似与数组的使用 length index
动态参数列表的方法 对应匹配的数组类型的方法是不能构成重载方法的
动态列表方法可以不传参数,但是数组的方法必须传递
动态参数列表在方法中只能存在一份,并且只能放在参数的末尾
15、面向对象的核心思想? 如何理解面向对象。
面向对象的三大特性:封装、继承、多态
16、成员变量和局部变量、静态变量
1、全局变量:直接在类中声明的变量叫成员变量(又称全局变量)。注:如果未对成员变量设置初始值,则系统会根据成员变量的类型自动分配初始值:int分配初始值0、boolean分配初始值false,而自定义类型则分配初始值null。
2、作用范围:成员变量定义后,其作用域是其所在的整个类。注:成员变量的定义没有先后顺序,但是最好将成员变量的定义集中在类的顶部。
3、局部变量:方法中的参数、方法中定义的变量和代码块中定义的变量统称为局部变量。注:局部变量在使用以前必须显式初始化或赋值,局部变量没有默认值。
注:声明局部变量时,数据类型前除final外不允许有其他关键字,即其定义格式为: [final] 数据类型 变量名 = 初始值;
4、作用范围:局部变量的作用域范围从定义的位置开始到其所在语句块结束。
5注意点:
1、如果局部变量的名字与全局变量的名字相同,则在局部变量的作用范围内全局变量被隐藏,即这个全局变量在同名局部变量所在方法内暂时失效。
2、如果在局部变量的作用域范围内访问该成员变量,则必须使用关键字this来引用成员变量。
静态变量
static变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。
static成员变量的初始化顺序按照定义的顺序进行初始化。
17 继承、多态,上下转型,实现接口。
多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。
多态的作用:消除类型之间的耦合关系
多态存在的三个必要条件
一、要有继承;
二、要有重写;
三、父类引用指向子类对象。
多态的好处
1.可替换性(substitutability)。多态对已存在代码具有可替换性。例如,多态对圆Circle类工作,对其他任何圆形几何体,如圆环,也同样工作。
2.可扩充性(extensibility)。多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。例如,在实现了圆锥、半圆锥以及半球体的多态基础上,很容易增添球体类的多态性。
3.接口性(interface-ability)。多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。如图8.3所示。图中超类Shape规定了两个实现多态的接口方法,computeArea()以及computeVolume()。子类,如Circle和Sphere为了实现多态,完善或者覆盖这两个接口方法。
4.灵活性(flexibility)。它在应用中体现了灵活多样的操作,提高了使用效率。
5.简化性(simplicity)。多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。
多态的分类:运行时多态和编译时多态。
上转型
向上转型。在多态中需要将子类的对象赋给父类引用,只有这样该引用才能够具备技能调用父类的方法和子类的方法。
向上转型时,子类单独定义的方法会丢失。比如上面Dog类中定义的run方法,当animal引用指向Dog类实例时是访问不到run方法的,animal.run()会报错。
子类引用不能指向父类对象。Cat c = (Cat)new Animal()这样是不行的。
向上转型的好处
减少重复代码,使代码变得简洁。
提高系统扩展性
下转型
下转型就是将父类的对象转为子类的对象。
向下转型注意事项:
向下转型的前提是父类对象指向的是子类对象(也就是说,在向下转型之前,它得先向上转型)
向下转型只能转型为本类对象(猫是不能变成狗的)
例如:
//还是上面的animal和cat dog
Animal a = new Cat();
Cat c = ((Cat) a);
c.eat();
//输出 我吃鱼
Dog d = ((Dog) a);
d.eat();
// 报错 : java.lang.ClassCastException:com.chengfan.animal.Cat cannot be cast to com.chengfan.animal.Dog
Animal a1 = new Animal();
Cat c1 = ((Cat) a1);
c1.eat();
// 报错 : java.lang.ClassCastException:com.chengfan.animal.Animal cannot be cast to com.chengfan.animal.Cat
继承
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
关键字 extends 表明正在构造的新类派生于一个已存在的类。已存在的类被称为超类(super class)、基类(base class)或父类(parent class);新类被称为子类(subclass)、派生类(derived class)或孩子类(child class)。
继承链中对象方法的调用的优先级:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。
一个类只能继承一个父类。
子类继承父类就继承了父类的不是private的属性和方法,子类也可以重写父类的方法,如果子类重写了父类的方法,子类的方法就会覆盖父类中的方法,子类如果想调用父类的方法就必须使用super关键字。
18 构造方法
1、构造方法的方法名必须与类名一样。
2、构造方法没有返回类型,也不能定义为void,在方法名前面不声明方法类型。
3、构造方法可以完成对属性的初始化以及和new 关键字一块创建对象的实例。
4、构造方法不能由编程人员调用,而要系统调用。
5、构造方法可以重载,以参数的个数,类型,或排序顺序区分。
6、如果类中不声明构造方法,系统会默认的把无参的构造方法当做此类的构造方法。
7、当执行构造方法时,会自动的现调用父类的构造方法,使用super关键字。
8、如果子类中有有参的构造函数,父类中没有声明无参的构造函数,则子类必须显示的调用父类的有参的构造函数,super(参数),否则就会报错。
9、在本类中也可以使用this关键字调用本类中的其他构造方法。但是必须要放在构造方法的首行。
19 this 关键字和super 关键字的区别
this代表它所在函数所属对象的引用。 简单说:哪个对象在调用this所在的函数,this就代表哪个对象。
this关键字的应用
(1)调用本类中的属性,也就是本类的成员变量。
(2)调用本类中的方法。
(3)调用本类中的其他构造函数,但是要放在构造函数的首行。
(4)使用this关键字调用当前对象。
(5)对象的比较
使用this时注意的事项
(1)this()调用其他构造方法的语句只能放在构造方法(在其他普通方法里是不行的)的首行;
(2)在使用this调用其他构造方法的时候,至少有一个构造方法是不用this调用的。(必须要有结尾,不能无限期的调用下去,循环递归调用);
super 关键字
super主要有两种用法:
1)super.成员变量/super.成员方法;
2)super(parameter1,parameter2…)
第一种用法主要用来在子类中调用父类的同名成员变量或者方法;
第二种主要用在子类的构造器中显示地调用父类的构造器,
要注意的是,如果是用在子类构造器中,则必须是子类构造器的第一个语句。
this 和 super 的区别
20、equals 和 == 的区别
(1)用来判断两个变量是否相等,如果是基本类型,则只要值相等,判断的结果就是true,例如65和‘A’比较,结果就是true。
(2)如果是比较的引用类型,那么只有在两个变量指向的是同一对象时才是true,例如String a=“111”,String a1=new String(“111”);他们比较的结果就是false,因为他们是两个对象。
(3)==是直接比较的两个对象的堆内存地址,如果相等,则说明这两个引用实际是指向同一个对象地址的。
(4)如果想要让两个只要内容相同的对象比较结果就是true,那么可以使用equals来比较,但是需要对equals进行重写。
equals默认情况下内部就是 == 比较,所以如果不重写的话,比较结果和 ==比较一样,如果重写了,就是比较对象的内容是否一样,注意在String中已经重写了equals方法,所以我们比较字符串的内容是否相等一般都是用equals方法。
21、接口和抽象类的区别
抽象类
(1)由abstact修饰的类是抽象类,由abstract 修饰的方法是抽象方法。
(2)有抽象方法的类一定是抽象类,但是抽象类不一定含有抽象方法。
(3)抽象类不能创建实例对象。
(4)抽象类中的抽象方法必须在子类中实现,不能有抽象构造方法或抽象静态方法。
(5)如果子类没有实现对应的抽象方法,则子类就必须设置成抽象类。
(6)普通方法是可以使用四种访问权限的,但抽象方法是有一个限制:不能用private 来修饰,也即抽象方法不能是私有的,否则,子类就无法继承实现抽象方法。
接口
接口(interface)可以说成是抽象类的一种特例,接口中的所有方法都必须是抽象的。接口中的方法定义默认为public abstract类型,接口中的成员变量类型默认为public static final。
下面比较一下两者的语法区别:
1.抽象类可以有构造方法,接口中不能有构造方法。
2.抽象类中可以有普通成员变量,接口中没有普通成员变量
3.抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。
-
抽象类中的抽象方法的访问类型可以是public,protected和(默认类型,虽然eclipse下不报错,但应该也不行),但接口中的抽象方法只能是public类型的,并且默认即为public abstract类型。
-
抽象类中可以包含静态方法,接口中不能包含静态方法
-
抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是public static final类型,并且默认即为public static final类型。
-
一个类可以实现多个接口,但只能继承一个抽象类。
22、内部类
1、成员内部类
1)成员内部类是外部类的一个成员,他可以无限制的访问外部类的属性和方法包括private修饰的。
注;
1)成员内部类中不能有任何static修饰的变量和方法。
2)可以使用任何的修饰符来修是成员内部类,只有创建了外部类才能够创建成员内部类。
创建内部类的实例对象的方法。
OutClass outclass = new OutClass();
OutClass.InnerClass innerClass = outclass.new InnerClass();
2、局部内部类
只有这个方法中才能调用这个局部内部类。
3、匿名类
1)匿名内部类没有构造方法,没有访问修饰符。
2)new 匿名内部类,写法上new 匿名内部类要实现的接口。
4、静态内部类
1)他的创建不需要依赖于外围类的。
2)他不能使用任何外围类的非static的成员变量和方法。
23 、四个权限修饰符
public>protected>默认类型(default)>private
1)private: Java语言中对访问权限限制的最窄的修饰符,一般称之为“私有的”。被其修饰的属性以及方法只能被该类的对象访问,其子类不能访问,更不能允许跨包访问。
2)default:即不加任何访问修饰符,通常称为“默认访问权限“或者“包访问权限”。该模式下,只允许在同一个包中进行访问。
3)protected: 介于public 和 private 之间的一种访问修饰符,一般称之为“保护访问权限”。被其修饰的属性以及方法只能被类本身的方法及子类访问,即使子类在不同的包中也可以访问。
4)public: Java语言中访问限制最宽的修饰符,一般称之为“公共的”。被其修饰的类、属性以及方法不仅可以跨类访问,而且允许跨包访问
24、final 关键字
类不能同时被声明为final和abstract。
1、final 修饰变量
被final修饰的变量必须显示的初始化,初始化可以以三种方式
1)定义时初始化
2)在构造器中设置值
3)在非静态块中为final实例变量设置值
final修饰变量指的是:这个变量被初始化后便不可改变,这里不可改变的意思对基本类型来说是其值不可变,而对于对象变量来说其引用不可变,即不能再指向其他的对象,但是对象的值是可以改变的。
2、修饰方法
被final修饰的方法不能被重写。
3、修饰类
被final修饰的类不能被继承。
注意:final修饰的类,类中的所有成员方法都被隐式地指定为final方法。
25、static 关键字
this关键字不能访问static修饰的变量,static关键字不能修饰局部变量
1、static方法,可以使用类名.直接调用,他不依赖与任何对象,不能使用this关键字调用。因为他不属于任何对象,所以不存在this关键字之说。
2、static变量也称为类变量,整个类共享,只在类加载的时候加载一次。
3、static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。
static的误区
1)Java中的static关键字不会影响到变量或者方法的作用域。在Java中能够影响到访问权限的只有private、public、protected(包括包访问权限)这几个关键字
功能:
修饰属性.方法,块,内部类
1、静态元素在;类加载的时候就被初始化,创建的很早,那时还没有创建对象
2、静态元素存储在静态元素区中,每一个类都有自己的一个单独的区域,与别的类不冲突
3、静态元素区不能被GC管理,可以简单的认为静态元素常驻内存
4、静态元素只加载一次,供全部的类对象和类本身共享
5、可以理解为静态元素与对象没有关系,它属于类
6、由于静态元素在加载的时候可能还没有创建对象,我们可以直接通过类名直接静态元素
7、静态元素可以直接访问静态元素。
8、非静态元素可以直接方法静态元素,但是静态元素不能直接方法非静态元素
9、静态元素中不可以使用this,super关键字
26、变量的初始化顺序
父类–静态变量/父类–静态初始化块
子类–静态变量/子类–静态初始化块
父类–变量/父类–初始化块
父类–构造器
子类–变量/子类–初始化块
子类–构造器
结论
1)子类的静态变量和静态初始化块的初始化是在父类的变量、初始化块和构造器初始化之前就完成了;
(2)静态变量、静态初始化块顺序取决于它们在类中出现的先后顺序
(3)变量、初始化块初始化顺序取决于它们在类中出现的先后顺序
27、default 关键字
default关键字可以让接口中的方法可以有默认的函数体,当一个类实现这个接口时,可以不用去实现这个方法
28、wait() 和 sleep()的区别
1)wait()是Object类中方法,sleep()是Thread类中方法。
2)调用sleep()方法,线程不会释放对象锁,但是wait() 会释放对象锁。
3)sleep()方法睡眠后不会释放资源,但是wait()会让出cpu供其他线程使用。
4)sleep()经过指定的时间后会自动唤醒,但是wait()需要notify()或者notifyAll()方法配合使用。
29、hashMap和hashtable的区别
1)继承不同,hashMap继承AbstractMap,hashtable继承Distionary。
2)两个都是实现的Map接口。
3)hashtable线程安全的,hashMap线程不安全。
4)hashtable中key和value都不允许出现null值,在hashMap中,null可以作为主键,但是只能有一个,可以有一个或多个对应的值为null。
5)哈希值使用不同,hashtable直接使用对象的hashcode,而hashMap需要重新计算hash值。
30 JDK 与JRE 的区别
1、JRE 是java运行的是环境,他包括java虚拟机,java核心类库和支持文件,不包括java开发工具,编译器,调试器和其他工具。
2|JDK是java开发工具包,是完整的java软件开发包,包含了JRE,编译器,和其他工具。
31、Integer 和 int 的区别
1)Integer是int的包装类,int是八种基本数据类型之一。
2)Integer是类,默认值为null,int 是基本数据类型,默认值是0.
3)Integer 表示的是对象,用一个引用指向这个对象,而int是基本数据类型,直接存储数值。
4)两个都是非new出来的Integer,如果数在-128到127之间,则是true,否则为false。因为java在编译Integer i2 = 128的时候,被翻译成:Integer i2 = Integer.valueOf(128);而valueOf()函数会对-128到127之间的数进行缓存。
5)两个都是new出来的,都为false。还是内存地址不一样。
6)int和Integer(无论new否)比,都为true,因为会把Integer自动拆箱为int再去比。
32、自动装箱和自动拆箱
自动拆箱和自动装箱是 JDK1.5 以后才有的功能,也就是java当中众多的语法之一,它的执行是在编译期,会根据代码的语法,在生成class文件的时候,决定是否进行拆箱和装箱动作。
1)自动装箱
将基本类型转换成包装类的过程。
2)自动拆箱
将包装类型装换成基本类型的过程
包装类 | 装箱 | 拆箱 |
---|---|---|
Byte | valueOf(String s)装箱成包装类 valueOf(String,int)根据指定进制装箱成包装类 | byteValue() |
Short | valueOf() | shortValue() |
Integer | valueOf() | intValue() |
Long | valueOf() | longValue() |
Float | valueOf() | floatValue() |
Double | valueOf() | doubleValue() |
Character | valueOf() | charValue() |
Boolean | valueOf() | booleanValue() |
33、基本类型和封装类的区别
1)基本类型是直接用来存储值得,放在栈中方便快速使用,封装类是类,其实例是对象,放在堆中。
2)基本类型不是对象,因此没有方法,包装类类型是类,因此有方法。
3)基本类型直接赋值即可,封装类需要使用new关键字创建实例对象,然后进行实例化。
4)封装类的默认值是null,而基本类型的默认值根据类型而定。(int 0,short (short)0,byte (byte)0,long 0L,char ‘\u0000’ , float0.0f ,double 0.0d,boolean false)
34、什么是泛型,泛型的好处。
定义:
1)泛型就是一种不确定的一种数据类型,这种数据类型只有在使用的时候才会确定。
2)泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样。
好处:
1)类型安全。 泛型的主要目标是提高 Java 程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。没有泛型,这些假设就只存在于程序员的头脑中(或者如果幸运的话,还存在于代码注释中)。
2)消除强制类型转换。 泛型的一个附带好处是,消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。
3)潜在的性能收益。 泛型为较大的优化带来可能。在泛型的初始实现中,编译器将强制类型转换(没有泛型的话,程序员会指定这些强制类型转换)插入生成的字节码中。但是更多类型信息可用于编译器这一事实,为未来版本的 JVM 的优化带来可能。由于泛型的实现方式,支持泛型(几乎)不需要 JVM 或类文件更改。所有工作都在编译器中完成,编译器生成类似于没有泛型(和强制类型转换)时所写的代码,只是更能确保类型安全而已。
35、ArrayList,LinkedList的异同点。
不同点:
1)ArrayList是基于动态数组的数据结构,每个元素在内存中存储地址是连续的LinkedList是基于链表的数据结构。
2)对于随机访问,Arraylist的效率要优于LinkedList,因为LinkedList要移动指针。
3)对于删除和新增数据,LinkedList要优于Arraylist,因为ArrayList要移动数据。
相同点
1)都是集成List接口,都是线程不安全的,有序可重复。
2)LinkedList和ArrayList都实现了Serializable接口,因此他支持序列化,能够通过序列化传输,实现了Cloneable接口,能被克隆. 同时ArrayList还实现了RandomAccess接口,支持快速随机访问,实际上就是通过下标序号进行快速访问.
36、HashSet、TreeSet、LinkedHashSet的异同点
一.HashSet
特点:
1.HashSet中不能有相同的元素,可以有一个Null元素,存入的元素是无序的。
2.HashSet如何保证唯一性?
1).HashSet底层数据结构是哈希表,哈希表就是存储唯一系列的表,而哈希值是由对象的hashCode()方法生成。
2).确保唯一性的两个方法:hashCode()和equals()方法。
3.添加、删除操作时间复杂度都是O(1)。
4.非线程安全
二.LinkedHashSet
特点:
1.LinkedHashSet中不能有相同元素,可以有一个Null元素,元素严格按照放入的顺序排列。
2.LinkedHashSet如何保证有序和唯一性?
1).底层数据结构由哈希表和链表组成。
2).链表保证了元素的有序即存储和取出一致,哈希表保证了元素的唯一性。
3.添加、删除操作时间复杂度都是O(1)。
4.非线程安全
三.TreeSet
特点:
1.TreeSet是中不能有相同元素,不可以有Null元素,根据元素的自然顺序进行排序。
2.TreeSet如何保证元素的排序和唯一性?
底层的数据结构是红黑树(一种自平衡二叉查找树)
3.添加、删除操作时间复杂度都是O(log(n))
4.非线程安全
5、集合中元素的类型需要实现Comparable才能实现排序。
三者都保证了元素的唯一性,如果无排序要求可以选用HashSet;如果想取出元素的顺序和放入元素的顺序相同,那么可以选用LinkedHashSet。如果想插入、删除立即排序或者按照一定规则排序可以选用TreeSet。
相同点;
都是继承Set接口,都不许有重复的元素,(如果输入相同的元素,只会保留第一次输入的元素)
36、HashMap的实现原理
HashMap由数组+链表组成的,数组的每个元素上都会引申一个链表,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的,如果定位到的数组位置不含链表(当前entry的next指向null),那么对于查找,添加等操作很快,仅需一次寻址即可;如果定位到的数组包含链表,对于添加操作,其时间复杂度为O(n),首先遍历链表,存在即覆盖,否则新增;对于查找操作来讲,仍需遍历链表,然后通过key对象的equals方法逐一比对查找。所以,性能考虑,HashMap中的链表出现越少,性能才会越好。
37、Set 和 Map 的联系
1)都有几个类型的集合。HashMap 和 HashSet ,都采 哈希表算法;TreeMap 和 TreeSet 都采用 红-黑树算法;LinkedHashMap 和 LinkedHashSet 都采用 哈希表算法和红-黑树算法。
2)分析 Set 的底层源码,我们可以看到,Set 集合 就是 由 Map 集合的 Key 组成。
38、悲观锁和乐观锁
1)悲观锁
总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。
2)乐观锁
总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。
39、java创建对象的几种方式
1)使用 new 关键字创建
2)使用反射创建 (newInstance()方法)
3)使用对象流创建
4) 使用Object类中clone方法创建,(需要继承Cloneable接口)
40、String,StringBuffer,StringBulider的区别
1)String 字符串常量,StringBuffer 字符串变量(线程安全),StringBulider 字符串变量(线程不安全)
2)对字符串经常改变的情况下尽量使用StringBuffer,因为如果是使用String,每改变一次字符串,内存中就多了一次无用的对象。造成的内存的浪费。
3)三个的效率 StringBulider>StringBuffer>String.
41、序列化,反序列化,Serialization接口
序列化;对象序列化的最主要的用处就是在传递和保存对象的时候,保证对象的完整性和可传递性。序列化是把对象转换成有序字节流,以便在网络上传输或者保存在本地文件中。序列化后的字节流保存了Java对象的状态以及相关的描述信息。序列化机制的核心作用就是对象状态的保存与重建。
(把对象转换为字节序列的过程称为对象的序列化。)
反序列化;客户端从文件中或网络上获得序列化后的对象字节流后,根据字节流中所保存的对象状态及描述信息,通过反序列化重建对象
(把字节序列恢复为对象的过程称为对象的反序列化。)
Serialization
1)Java类通过实现java.io.Serialization接口来启用序列化功能,未实现此接口的类将无法将其任何状态或者信息进行序列化或者反序列化。可序列化类的所有子类型都是可以序列化的。序列化接口没有方法或者字段,仅用于标识可序列化的语义。
2)当试图对一个对象进行序列化时,如果遇到一个没有实现java.io.Serialization接口的对象时,将抛出NotSerializationException异常。
3)如果要序列化的类有父类,要想将在父类中定义过的变量序列化下来,那么父类也应该实现java.io.Serialization接口。
42、transient 关键字的作用
1)继承Serializable接口实现序列化,Serializable自动化完成序列
2)transient关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。、
3)被transient关键字修饰的变量不再能被序列化。
4)一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。也可以认为在将持久化的对象反序列化后,被transient修饰的变量将按照普通类成员变量一样被初始化。
43、多线程中常用的方法
1.start()和run()
start()方法是是开启线程的方法,这个方法执行后,一个线程才真正的进入RUNNABLE状态。run()方法是线程中具体执行的业务活动,一般都要重写run()方法。
2.stop()
stop()方法在结束线程时,会直接终止线程,并立即释放这个线程所持有的锁,而锁恰恰是用来维护对象一致性的。例如写线程正在写到一半,线程被强行终止,对象就会被写坏了,同时锁已经释放,其他对象读到这个对象是写坏了的对象。
3.interrupt()、isInterrupted()、interrupted()
interrupt()方法是一个实例方法,它通知目标线程中断,也就是设置中断标志位。相当于给线程发送一个通知,告知要人希望你退出了。至于目标线程以后怎么处理看目标线程自己的了。isInterrupted()方法也是实例方法,他判断当前线程是否被中断。interrupted()是个静态方法,可用来判断当前线程的中断状态,同时会清除当前线程的中断标志位状态。
4.sleep()
sleep()方法是让当前线程休眠若干时间,它会抛出一个InterruptedException中断异常。这个异常不是运行时异常,必须捕获且处理,当线程在sleep()休眠时,如果被中断,这个异常就会产生。一旦被中断后,抛出异常,会清除标记位,如果不加处理,下一次循环开始时,就无法捕获这个中断,故一般在异常处理时再设置标记位。sleep()方法不会释放任何对象的锁资源。
5.wait()和notify()
wait()等待方法,是Object类中的方法,当一个对象实例上调用wait()方法后,当前线程就会在这个对象上等待。那么等待什么时候结束呢?线程一直等到其他线程调用了这个对象的notify()方法为止。这样实例对象就成了多个线程间的通信手段。wait()和notify()不能随便调用,它必须包含在对应的synchronize语句中,这俩方法,都需要首先获得目标对象的一个监听器,而wait()和notify()方法在执行后会释放这个监听器。wait()方法会释放目标对象的锁。
6.suspend()和resume()
suspend()方法挂起线程,resume()方法继续执行,被挂起的线程必须等到resume()才能继续指定。suspend()方法在导致线程暂停的同时,并不会释放任何锁资源,而其他线程要访问被它占用的锁时会被牵连导致无法正常运行,只到遇到resume()操作才能继续。被suspend挂起的线程,从 它的线程状态来看,居然还是RUNNABLE,会影响判断。因此这俩方法已经被废弃,不建议使用。
7.join()和yeild()
join()方法表示无限的等待,他会一直阻塞当前线程,只到目标线程执行完毕。join(long millis) 给出了一个最大等待时间,如果超过给定的时间目标线程还在执行,当前线程就不等了,继续往下执行。
yeild()方法是个静态方法,一旦执行,他会使当前线程让出CPU。让出CPU不代表当前线程不执行了,还会进行CPU资源的争夺。如果一个线程不重要或优先级比较低,可以调用这个方法,把资源给重要的线程去做。
8.volatile
当用事volatile声明一个变量的时候,就是告诉虚拟机,这个变量极有可能会被某些程序或者线程修改。为了确保修改后,所有线程能看到这个改动,虚拟机会采取一些手段保证这个变量的可见性。
9.守护线程和用户线程
守护线程是系统的守护者,在后台默默的完成系统性服务,比如垃圾回收线程、JIT线程等。用户线程是系统的工作线程,完成这个系统要完成的因为操作,如果所有的用户线程结束了,那么守护线程也就不存在了,整个程序也就结束了。当一个Java应用里只有守护线程时,Java虚拟机会自然退出。
设置守护线程必须在start()之前设置,Thread.setDaemon(true)。
10.synchronize
synchronize关键字的作用是实现线程间的同步。它的工作是对同步代码加锁,使得每次只能有一个线程能进入代码块,从而保证了线程间的安全性。使用方法:知道加锁对象,直接作用于实例方法,直接作用于静态方法。
44、什么是进程,什么是线程,进程和线程之间的区别
进程可以认为是程序执行时的一个实例。进程是系统进行资源分配的独立实体, 且每个进程拥有独立的地址空间。一个进程无法直接访问另一个进程的变量和数据结构, 如果希望让一个进程访问另一个进程的资源,需要使用进程间通信,比如:管道,文件, 套接字等。
一个进程可以拥有多个线程,每个线程使用其所属进程的栈空间。 线程与进程的一个主要区别是,同一进程内的多个线程会共享部分状态, 多个线程可以读写同一块内存(一个进程无法直接访问另一进程的内存)。同时, 每个线程还拥有自己的寄存器和栈,其它线程可以读写这些栈内存
线程是进程的一个实体,是进程的一条执行路径
线程进程的区别体现在几个方面:
1)地址空间和其它资源(如打开文件):进程间相互独立,同一进程的各线程间共享。某进程内的线程在其它进程不可见。
2)通信:进程间通信IPC(管道,信号量,共享内存,消息队列),线程间可以直接读写进程数据段(如全局变量)来进行通信——需要进程同步和互斥手段的辅助,以保证数据的一致性。
3)调度和切换:线程上下文切换比进程上下文切换要快得多。
4)在多线程OS中,进程不是一个可执行的实体。
45、 线程的状态以及转换方式
新建线程new,启动线程runnable,阻塞block,限时等待timed_waiting,等待线程waiting,终止线程terminated
45、OSIS7层模型 TCp/IP层模型
OSI中的层 功能 TCP/IP协议族
应用层 文件传输/电子邮件/文件服务/虚拟终端 TFTP,HTTP,SNMP TCP/IP,TFP,SMTP,DNS,Telnet
表示层 数据格式化,代码转换,数据加密 没有协议
会话层 解除或建立与别的节点的联系 没有协议
传输层 提供端对端的接口 TCP UDP
网络层 为数据包选择路由 IP, ICMP,RIP,OSPF,BGP,IGMP
数据链路层 传输有地址的帧以及错误检测功能 SLIP,CSLIP,PPP,ARP,RARP,MTU
物理层 以二进制数据的形式在物理媒体上传输数据 ISO2110,IEEE802,IEE802.2
46、谈谈你所了解的设计模式
1.单例设计模式
2.工厂设计模式
3.代理模式
4.观察者设计模式
5.适配器模式
6.策略模式
7.门面模式
8.桥接模式
47、List、Set和Map的特点和区别
List:
1.可以允许重复的对象。
2.可以插入多个null元素。
3.是一个有序容器,保持了每个元素的插入顺序,输出的顺序就是插入的顺序。
4.常用的实现类有 ArrayList、LinkedList 和 Vector。ArrayList 最为流行,它提供了使用索引的随意访问,而 LinkedList 则对于经常需要从 List 中添加或删除元素的场合更为合适。
Set:
1.不允许重复对象
2.无序容器,你无法保证每个元素的存储顺序,TreeSet通过 Comparator 或者 Comparable 维护了一个排序顺序。
3.只允许一个 null 元素
4.Set 接口最流行的几个实现类是 HashSet、LinkedHashSet 以及 TreeSet。最流行的是基于 HashMap 实现的 HashSet;TreeSet 还实现了 SortedSet 接口,因此 TreeSet 是一个根据其 compare() 和 compareTo() 的定义进行排序的有序容器。
Map:
1.不是collection的子接口或者实现类。Map是一个接口。
2.Map 的 每个 Entry 都持有两个对象,也就是一个键一个值,Map 可能会持有相同的值对象但键对象必须是唯一的。
3.TreeMap 也通过 Comparator 或者 Comparable 维护了一个排序顺序。
4.Map 里你可以拥有随意个 null 值但最多只能有一个 null 键。
5.Map 接口最流行的几个实现类是 HashMap、LinkedHashMap、Hashtable 和 TreeMap。(HashMap、TreeMap最常用)
48.io流部分
java基础之利用递归对文件的遍历和删除
java基础之文件(File)
java基础之输入流和输出流(FileInputStream,FileOutputStream,FileReader,FileWriter)
java基础之文件的复制,删除,剪切(利用递归)
java基础之缓存流(BufferedInputStream,BufferedOutputStream,BufferedReader,BufferedWriter)
49.反射
java基础之反射以及Class类的使用与理解
50注解
java基础之注解的理解与应用