目录
- 简述static和final的用法
- 方法的重载和重写
- 构造器Constructor是否可被override?
- Error和Exception的区别
- 写出常见的5个RuntimeException
- abstract class 抽象类 和 interface 接口 的区别
- this 和 super 的区别
- "=="和equals方法的区别
- String、StringBuffer和StringBuilder的区别?
- 谈谈你对面向对象的理解??
- 有了基本数据类型,为什么还需要包装类型?
- Java中的集合及其区别
- ArrayList和LinkedList的区别
- HashMap和HashTable的区别
- Collection 和 Collections的区别
- 多线程有几种实现方法,都是什么?同步有几种实现方法,都是什么?
- 线程的几种实现方式区别
- .sleep()和wait()有什么区别?
- 1.6 java中会存在内存泄露吗?请简单描述。
- 1.32 GC是什么? 为什么要有GC?
- 1.36 解释内存中的栈(stack)、堆(heap)和静态区(static area)的用法
- 1.45 阐述final、finally、finalize的区别。
- 1.52 如何通过反射创建对象?
- 1.53 谈谈 JVM 的内存结构和内存分配?
简述static和final的用法
-
static:修饰属性,方法,代码块
1)静态属性:也可叫类变量,通过类名.属性名
直接访问。
注意:类中的实例变量是在创建对象时被初始化的;
被static修饰的属性,也就是类变量,是在类加载时被创建并进行初始化,类加载的过程是一次,也就是类变量只会被创建一次。
2)静态方法:通过类名.方法名
直接访问 。
注意:static修饰的方法,不能直接访问本类中的非静态(static)成员(包括方法和属性);但是本类的非静态方法可以访问本类的静态成员(包括方法和属性),可以调用静态方法。(静态资源只能调静态,普通资源随便调)
3)静态代码块static{}
:随着类的加载而加载,且只被加载一次;位置:类里方法外;优先于对象先加载进内存。 -
final:修饰变量,类,方法
(1)变量:
被fianl修饰的成员变量就是常量(常量名大写),一旦赋值不能改变。
修饰局部变量:修饰基本数据类型 -> 变量的值不能改变
修饰引用 -> 引用只能指向固定的对象
修饰实例变量:默认值不生效,可以再赋值
(2)方法 :不能被子类重写;不能修饰构造方法
(3)类:不能被继承;final类中的所有方法,默认都是final的。
方法的重载和重写
- 重载:指在一个类中定义多个同名的方法,但每个方法的参数列表(参数的个数和类型)不同。
- 重写:
1)继承后,子类拥有了父类的功能,可对父类的原有功能进行修改;
2)子类中的方法声明(即方法返回值、方法名和参数列表)与父类一致时,会发生覆盖/重写;
3)父类的私有方法不能被重写;父类的构造方法不能被继承;
4)重写时,子类的修饰符要大于等于父类的。
构造器Constructor是否可被override?
构造器Constructor不能被继承,因此不能重写Override,但可以被重载Overload。
每一个类必须有自己的构造函数,负责构造自己这部分的构造。子类不会覆盖父类的构造函数,相反必须负责在一开始调用父类的构造函数。
Error和Exception的区别
- Error:表示系统级的错误和程序不必处理的异常,
是恢复不是不可能但很困难的情况下的一种严重问题,
比如内存溢出,不可能指望程序能处理这样的情况。 - Exception:表示需要捕捉或者需要程序进行处理的异常,是一种设计或实现问题;也就是说,它表示如果程序运行正常,从不会发生的情况。
写出常见的5个RuntimeException
(1)java.lang.NullPointerException空指针异常,出现原因:调用了未经初始化的对象或者不存在的对象。
(2)ClassNoFoundException 指定类找不到,出现原因:类的名称和路径加载错误,通常是试图通过字符串来加载某个类时可能引发异常。
(3)NumberFormatException字符串转换为数字异常,出现原因:字符串数据中包含非数字型字符。
(4)IndexOutOfBoundsException数组下标越界异常
(5)IllegalArgumentException 方法传递参数错误
(6)ClassCastException数据类型转换异常
(7)NoClassDefFoundExcetion 未找到类定义错误
(8)SQLException SQL异常
(9)InstantiationException实例化异常
(10)NoSuchMethodExceptioin 方法不存在异常
abstract class 抽象类 和 interface 接口 的区别
- 相同点:
1)都是抽象类,不能实例化;
2)接口实现类和抽象类的子类都必须要实现已经声明的抽象方法。 - 不同点:
1) 关键字: 分别是 abstract 和 interface
2) 与类的关系:
抽象类被子类继承,用关键字extends(类与类之间是单继承);
接口被类实现,用关键字implements(一个类可以实现多个接口,接口与接口间多继承)。
3)构造方法:
抽象类不能创建对象,但可以有构造方法,为了方便子类创建对象;
接口不可以有构造方法,
为什么还能创建对象?Inter inter=new InterImpl();
–创建对象时调用了实现类自己的无参构造,且实现类的无参构造第一行隐藏了super();
,这个super实际调用的是默认Object类的无参构造。
4)变量:
抽象类可以有成员变量和常量,也可以是私有的,其值可在子类重新定义并赋值;
接口会把变量自动拼接成常量(public static final),实现类中不可以重新定义赋值。
5)方法:抽象类可以有普通方法、抽象方法,也可以没有抽象方法,可以私有;接口中都是公共的抽象方法,会给方法自动进行拼接(public abstract)。
this 和 super 的区别
- this 代表本类对象的引用;super 代表父类对象的引用;
- this 用来区分局部变量和成员变量;super 用来区分本类变量和父类变量;
- 使用:
this.成员变量
,this.成员方法()
,this([参数])
代表调本类构造方法;
super.成员变量
,super.成员方法()
,super([参数])
代表调父类构造方法; - this() 和 super() 不能同时出现在同一个构造方法,因为它们都必须在构造方法的第一行进行调用。
"=="和equals方法的区别
-
“==”:比较两个基本类型的值,是比较值本身,也就是比较变量所对应的内存中所存储的数值是否相同;比较两个引用类型的值,是比较地址值。
-
equals:用于比较两个独立对象的内容是否相同,即比较两个对象的属性值是否相同。
注意:需要重写 equals() 。因为使用Object提供的默认的 equals() 时,底层使用的是 “==” 比较。
String、StringBuffer和StringBuilder的区别?
- 在运行速度或执行速度上,快慢为:StringBuilder > StringBuffer > String
- 在线程安全上,StringBuilder是线程不安全的,而StringBuffer是线程安全的
- 适用场景:
String:适用于少量的字符串操作的情况
StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况
StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况
谈谈你对面向对象的理解??
所谓的面向对象就是将我们的程序模块化,对象化,把具体事物的特性属性和通过这些属性来实现一些动作的具体方法放到一个类里面,这就是封装。封装是我们所说的面相对象编程的特征之一。
除此之外还有继承和多态。继承有点类似与我们生物学上的遗传,就是子类的一些特征是来源于父类的,儿子遗传了父亲或母亲的一些性格,或者相貌,又或者是运动天赋。有点种瓜得瓜种豆得豆的意思。面向对象里的继承也就是父类的相关的属性,可以被子类重复使用,子类不必再在自己的类里面重新定义一回,父类里有我们只要拿过来用就好了。而对于自己类里面需要用到的新的属性和方法,子类就可以自己来扩展了。当然,会出现一些特殊情况,就是我们在有一些方法在父类已经定义好了,但是子类我们自己再用的时候,发现,其实,我们的虽然都是计算工资的,但是普通员工的工资计算方法跟经理的计算方法是不一样的,所以这个时候,我们就不能直接调用父类的这个计算工资的方法了。这个时候我们就需要用到面向对象的另一个特性,多态。
对,就是多态,我们要在子类里面把父类里面定义计算工资的方法在子类里面重新实现一遍。多态包含了重载和重写。重写很简单就是把子类从父亲类里继承下来的方法重新写一遍,这样,父类里相同的方法就被覆盖了,当然啦,你还是可以通过super.CaculSalary方法来调用父类的工资计算方法。而重载就是类里面相同方法名,不同形参的情况,可以是形参类型不同或者形参个数不同,或者形参顺序不同,但是不能使返回值类型不同。
有了基本数据类型,为什么还需要包装类型?
我们知道Java是一个面相对象的编程语言,基本类型并不具有对象的性质,为了让基本类型也具有对象的特征,就出现了包装类型(如我们在使用集合类型Collection时就一定要使用包装类型而非基本类型),它相当于将基本类型“包装起来”,使得它具有了对象的性质,并且为其添加了属性和方法,丰富了基本类型的操作。
另外,当需要往ArrayList,HashMap中放东西时,像int,double这种基本类型是放不进去的,因为容器都是装object的,这是就需要这些基本类型的包装类了。
Java中的集合及其区别
- List(列表):继承自Collection接口,元素有序,有下标,允许重复元素;线性存储,长度可动态改变
- Set(集):继承自Collection接口,元素无序,无下标,不允许重复元素
- Map(映射):元素无序,长度可动态改变;以键-值对方式存储,且键不允许重复,否则value会被覆盖
ArrayList和LinkedList的区别
- ArrayList底层是基于动态数组的数据结构,适合查询。
- LinkedList底层是基于链表的数据结构,适合新增、删除。
HashMap和HashTable的区别
在Java 2以前,一般使用HashTable来映射键值和元素。为了使用Java集合框架,Java对HashTable进行了重新设计,但是,为了向后兼容,保留了所有的方法。HashTable实现了Map接口,除了HashTable具有同步功能之外,它与HashMap的用法是一样的。
在使用时一般是用ArrayList代替Vector,LinkedList代替Stack,HashMap代替HashTable,即使在多线程中需要同步,也是用同步包装类。
Collection 和 Collections的区别
- Collection是java.util下的接口,它是各种集合的父接口,继承于它的接口主要有Set 和List;
- Collections是个java.util下的类,是针对集合的工具类,提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。
多线程有几种实现方法,都是什么?同步有几种实现方法,都是什么?
- 多线程有两种实现方法:继承Thread类或者实现Runnable接口。
- 实现同步也有两种方法:一种是同步方法,另一种是同步代码块。
同步方法是在方法返回类型前面加上synchronized关键字
同步代码块是synchronized (这里写需要同步的对象){…}
线程的几种实现方式区别
- extends Thread
- implements Runnable
- implements Callable
Runnable和Callable的区别是,
(1)Callable规定的方法是call(),Runnable规定的方法是run()。
(2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。
(3)call方法可以抛出异常,run方法不可以 。
(4)运行Callable任务可以拿到一个Future对象,表示异步计算的结果。
.sleep()和wait()有什么区别?
- Thread类的方法:sleep(),yield()等
Object的方法:wait(),notify()等 - 每个对象都有一个锁来控制同步访问。Synchronized关键字可以和对象的锁交互,来实现线程的同步。
sleep方法没有释放锁;
wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。 - wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用。
- sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常。
1.6 java中会存在内存泄露吗?请简单描述。
答:内存泄露是指系统中存在无法回收的内存,
有时候会造成内存不足或系统崩溃。Java存在内存泄露。
Java中的内存泄露当然是指:存在无用但是垃圾回收器无法回收的对象。
而且即使有内存泄露问题存在,也不一定会表现出来。
自己实现堆栈的数据结构时有可能会出现内存泄露。
1.32 GC是什么? 为什么要有GC?
GC是垃圾收集的意思,内存处理是编程人员容易出现问题的地方,
忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,
Java语言没有提供释放已分配内存的显示操作方法。Java程序员不用担心内存管理,因为垃圾收集器会自动进行管理。要请求垃圾收集,可以调用下面的方法之一:System.gc()或Runtime.getRuntime().gc(),但JVM可以屏蔽掉显示的垃圾回收调用。
垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存。垃圾回收器通常是作为一个单独的低优先级的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。
在Java诞生初期,垃圾回收是Java最大的亮点之一,因为服务器端的编程需要有效的防止内存泄露问题,然而时过境迁,如今Java的垃圾回收机制已经成为被诟病的东西。移动智能终端用户通常觉得iOS的系统比Android系统有更好的用户体验,其中一个深层次的原因就在于Android系统中垃圾回收的不可预知性。
1.36 解释内存中的栈(stack)、堆(heap)和静态区(static area)的用法
答:通常我们定义一个基本数据类型的变量,一个对象的引用,还有就是函数调用的现场保存都使用内存中的栈空间;而通过new关键字和构造器创建的对象放在堆空间;程序中的字面量(literal)如直接书写的100、”hello”和常量都是放在静态区中。栈空间操作起来最快但是栈很小,通常大量的对象都是放在堆空间,理论上整个内存没有被其他进程使用的空间甚至硬盘上的虚拟内存都可以被当成堆空间来使用。
1.45 阐述final、finally、finalize的区别。
答:
- final:修饰符(关键字)有三种用法:如果一个类被声明为final,意味着它不能再派生出新的子类,即不能被继承,因此它和abstract是反义词。将变量声明为final,可以保证它们在使用中不被改变,被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取不可修改。被声明为final的方法也同样只能使用,不能在子类中被重写。
- finally:通常放在try…catch…的后面构造总是执行代码块,这就意味着程序无论正常执行还是发生异常,这里的代码只要JVM不关闭都能执行,可以将释放外部资源的代码写在finally块中。
- finalize:Object类中定义的方法,Java中允许使用finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在销毁对象时调用的,通过重写finalize()方法可以整理系统资源或者执行其他清理工作。
1.52 如何通过反射创建对象?
答:
- 方法1:通过类对象调用newInstance()方法,例如:String.class.newInstance()
- 方法2:通过类对象的getConstructor()或getDeclaredConstructor()方法获得构造器(Constructor)对象并调用其newInstance()方法创建对象,例如:String.class.getConstructor(String.class).newInstance(“Hello”);
1.53 谈谈 JVM 的内存结构和内存分配?
Java 内存模型
Java 虚拟机将其管辖的内存大致分三个逻辑部分:方法区(Method Area)、 Java 栈和 Java 堆。
1、方法区是静态分配的,编译器将变量绑定在某个存储位置上,而且这些绑定不会在运行时改变。常数池,源代码中的命名常量、 String 常量和 static 变量保存在方法区。
2、 Java Stack 是一个逻辑概念,特点是后进先出。一个栈的空间可能是连续的,也可能是不连续的。最典型的 Stack 应用是方法的调用, Java 虚拟机每调用一次方法就创建一个方法帧(frame),退出该
方法则对应的 方法帧被弹出(pop)。栈中存储的数据也是运行时确定的。
3、 Java 堆分配(heap allocation)意味着以随意的顺序,在运行时进行存储空间分配和收回的内存管理模型。堆中存储的数据常常是大小、数量和生命期在编译时无法确定的。 Java 对象的内存总是在 heap 中分配。
b) java 内存分配
1、基础数据类型直接在栈空间分配;
2、方法的形式参数,直接在栈空间分配,当方法调用完成后从栈空间回收;
3、引用数据类型,需要用 new 来创建,既在栈空间分配一个地址空间,又在堆空间分配对象的类变量;
4、方法的引用参数,在栈空间分配一个地址空间,并指向堆空间的对象区,当方法调用完后从栈空间回收;
5、局部变量 new 出来时,在栈空间和堆空间中分配空间,当局部变量生命周期结束后,栈空间立刻被回收,堆空间区域等待 GC 回收;
6、方法调用时传入的实际参数,先在栈空间分配,在方法调用完成后从栈空间释放;
7、字符串常量在 DATA 区域分配 , this 在堆空间分配;
8、数组既在栈空间分配数组名称, 又在堆空间分配数组实际的大小。