J2SE基础

1.九种基本数据类型的大小

java提供了一组基本数据类型,包括:boolean,byte,char,short,int,long,float,double(注:事实上应该是八种基本数据类型,String类并不属于基本类型。)

同时,java也为其提供了相应的封装类:

Boolean,Byte,Character,Short,Integer,Long,Float,Double.


其中boolean比较特别,在Java虚拟机中没有任何供boolean值专用的字节码指令,Java语言表达式所操作的boolean值,在编译之后都使用Java虚拟机中的int数据类型来代替,而boolean数组将会被编码成Java虚拟机的byte数组,每个元素boolean元素占8位”。这样我们可以得出boolean类型占了单独使用是4个字节,在数组中又是1个字节。

为什么要这么做?

在java中使用基本类型来存储语言支持的基本数据类型,这里没有采用对象,而是使用了传统的面向过程语言所采用的基本类在型,主要是从性能方面来考虑的:因为即使最简单的数学计算,使用对象来处理也会引起一些开销,而这些开销对于数学计算本来是毫无必要的。但是在java中,泛型类包括预定义的集合,使用的参数都是对象类型,无法直接使用这些基本数据类型,所以java又提供了这些基本类型的包装器。而对基本数据类型封装之后,封装类有可以有方法和属性,然后就可以利用这些方法和属性来处理数据。

2.Switch能否用string做参数?

char int byte short可以(会自动转换为int),在java7以后可以用string做参数,其实通过调用switch中string.hashCode,将string转换为int从而进行判断

3.equals与==的区别。

“==”是运算符,而equals是object里面的一个方法。对于基本类型,用“==”可以比较大小,看两个元素是否相等,equals没有什么用。对于对象之间的比较,“==”是比较两个对象的内存地址是否相等,equals在object也是使用“==”实现的,所以不重写equals的类使用效果是一样的,但是我们一般都会在子类中重写该方法,比较两个对象的内容是否一样。

4.object有哪些公用方法

clone():保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常。

hashCode():该方法用于哈希查找,重写了equals方法一般都要重写hashCode方法。这个方法在一些具有哈希功能的Collection中用到。

getClass():final方法,获得运行时类型。

wite():使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait()方法一直等待,直到获得锁或者被中断。wait(long timeout)设定一个超时间隔,如果在规定时间内没有获得锁就返回。

调用该方法后当前线程进入睡眠状态,直到以下事件发生:

1. 其他线程调用了该对象的notify方法

2. 其他线程调用了该对象的notifyAll方法

3. 其他线程调用了interrupt中断该线程

4. 时间间隔到了

此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常

notify():唤醒在该对象上等待的某个线程。

notifyAll():唤醒在该对象上等待的所有线程。

toString():转换成字符串,一般子类都有重写,否则打印句柄。

5.java的四种引用,强弱软虚

强:只要某个对象有强引用与之关联,JVM必定不会回收这个对象,即使在内存不足的情况下,JVM宁愿抛出OutOfMemory错误也不会回收这种对象。

软:用来描述一些有用但并不是必需的对象,在Java中用java.lang.ref.SoftReference类来表示。对于软引用关联着的对象,只有在内存不足的时候JVM才会回收该对象。因此,这一点可以很好地用来解决OOM的问题,并且这个特性很适合用来实现缓存:比如网页缓存、图片缓存等。软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被JVM回收,这个软引用就会被加入到与之关联的引用队列中。

弱:用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。在java中,用java.lang.ref.WeakReference类来表示。下面是使用示例:

importjava.lang.ref.WeakReference;

publicclassMain {

publicstaticvoidmain(String[] args) {

WeakReferencesr =newWeakReference(newString("hello"));

System.out.println(sr.get());

System.gc();//通知JVM的gc进行垃圾回收

System.out.println(sr.get());

}

}

虚:虚引用和前面的软引用、弱引用不同,它并不影响对象的生命周期。在java中用java.lang.ref.PhantomReference类表示。如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。

要注意的是,虚引用必须和引用队列关联使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会把这个虚引用加入到与之 关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。

进一步使用:

对于强引用,我们平时在编写代码时经常会用到。而对于其他三种类型的引用,使用得最多的就是软引用和弱引用,这2种既有相似之处又有区别。它们都是用来描述非必需对象的,但是被软引用关联的对象只有在内存不足时才会被回收,而被弱引用关联的对象在JVM进行垃圾回收时总会被回收。针对上面的特性,软引用适合用来进行缓存,当内存不够时能让JVM回收内存,弱引用能用来在回调函数中防止内存泄露。因为回调函数往往是匿名内部类,隐式保存有对外部类的引用,所以如果回调函数是在另一个线程里面被回调,而这时如果需要回收外部类,那么就会内存泄露,因为匿名内部类保存有对外部类的强引用。

6.Hashcode的作用

1、hashCode的存在主要是用于查找的快捷性,如Hashtable,HashMap等,hashCode是用来在散列存储结构中确定对象的存储地址的;

2、如果两个对象相同,就是适用于equals(java.lang.Object) 方法,那么这两个对象的hashCode一定要相同;

3、如果对象的equals方法被重写,那么对象的hashCode也尽量重写,并且产生hashCode使用的对象,一定要和equals方法中使用的一致,否则就会违反上面提到的第2点;

7.ArrayList、LinkedList、Vector的区别

arraylist和vector是采用数组方式存储数据的,此数据元素数大于实际存储的数据以便增加和插入元素,都允许直接序号索引元素,但是插入数据要涉及到元素的移动等内存操作,所以索引数据快,插入数据慢,vector由于使用了synchronized,所以性能上要比arraylist差,linkedlist使用了双向链表存储数据,按序列号索引数据需要向前或向后遍历,但是插入数据只需要记录本项的前后项即可,所以插入数据快。

8.String、StringBuffer与StringBuilder的区别

String:字符串常量

StringBuffer:字符串变量(线程安全)

StringBuilder:字符串变量(线程不安全)

对于三者使用的总结

 1.如果要操作少量的数据用 = String

2.单线程操作字符串缓冲区 下操作大量数据 = StringBuilder

3.多线程操作字符串缓冲区 下操作大量数据 = StringBuffer

9.Map、Set、List、Queue、Stack的特点与用法

map:一组成对的“键值对”对象

set:没有顺序,不重复(数学中的集合)

list:有顺序,可重复

queue:优先级队列

stack:栈

10.HashMap和HashTable的区别

HashMap和Hashtable都实现了Map接口,但决定用哪一个之前先要弄清楚它们之间的分别。主要的区别有:线程安全性,同步(synchronization),以及速度。

1.HashMap几乎可以等价于Hashtable,除了HashMap是非synchronized的,并可以接受null(HashMap可以接受为null的键值(key)和值(value),而Hashtable则不行)。

2.HashMap是非synchronized,而Hashtable是synchronized,这意味着Hashtable是线程安全的,多个线程可以共享一个Hashtable;而如果没有正确的同步的话,多个线程是不能共享HashMap的。Java 5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的扩展性更好。

3.另一个区别是HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。这条同样也是Enumeration和Iterator的区别。

4.由于Hashtable是线程安全的也是synchronized,所以在单线程环境下它比HashMap要慢。如果你不需要同步,只需要单一线程,那么使用HashMap性能要好过Hashtable。

5.HashMap不能保证随着时间的推移Map中的元素次序是不变的。

11.HashMap和ConcurrentHashMap的区别,HashMap的底层源码

Hashmap本质是数组加链表。根据key取得hash值,然后计算出数组下标,如果多个key对应到同一个下标,就用链表串起来,新插入的在前面。

ConcurrentHashMap:在hashMap的基础上,ConcurrentHashMap将数据分为多个segment,默认16个(concurrency level),然后每次操作对一个segment加锁,避免多线程锁的几率,提高并发效率。

HashMap的底层主要是基于数组和链表来实现的,它之所以有相当快的查询速度主要是因为它是通过计算散列码来决定存储的位置,能够很快的计算出对象所存储的位置。HashMap中主要是通过key的hashCode来计算hash值的,只要hashCode相同,计算出来的hash值就一样。如果存储的对象对多了,就有可能不同的对象所算出来的hash值是相同的,这就出现了所谓的hash冲突。学过数据结构的同学都知道,解决hash冲突的方法有很多,HashMap底层是通过链表来解决hash冲突的。

12.TreeMap、HashMap、LindedHashMap的区别

LinkedHashMap保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的.也可以在构造时用带参数,按照应用次数排序。在遍历的时候会比HashMap慢,不过有种情况例外,当HashMap容量很大,实际数据较少时,遍历起来可能会比LinkedHashMap慢,因为LinkedHashMap的遍历速度只和实际数据有关,和容量无关,而HashMap的遍历速度和他的容量有关。

TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。

一般情况下,我们用的最多的是HashMap,HashMap里面存入的键值对在取出的时候是随机的,它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度。在Map 中插入、删除和定位元素,HashMap 是最好的选择。

TreeMap取出来的是排序后的键值对。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。

LinkedHashMap 是HashMap的一个子类,如果需要输出的顺序和输入的相同,那么用LinkedHashMap可以实现,它还可以按读取顺序来排列,像连接池中可以应用。

13.Collection包结构,与Collections的区别

Collection是集合类的上级接口,子接口主要有Set和List。


Collections是针对集合类的一个帮助类,不能被实例化,提供了操作集合的工具方法:一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。

14.try catch finally,try里有return,finally还执行么?

会执行,程序会先执行finally中的代码然后执行return

15.Excption与Error包结构。OOM你遇到过哪些情况,SOF你遇到过哪些情况


Throwable是所有异常和错误的父类,有两个子类Exception和Error,其中异常类Exception又分为运行时异常和非运行时异常,这两种异常有很大差异,又分为非检查异常和检查异常。从责任的角度看error是jvm需要负担的责任,runtiemexception是程序应该负担的责任,非运行时异常是具体应用负担的责任。

Error:

Error是程序无法处理的错误,比如OutOfMemoryError,ThreadDeath等,java虚拟机抛出error对象,程序不捕获或抛出error对象,这些异常发生时,jvm一般会终止线程。

16.Java面向对象的三个特征与含义。

封装:即把对象的全部属性和全部服务结合在一起,形成一个不可分割的单位,尽可能隐藏对象的内部结构。这个对象只对外公布需要公开的属性和行为,而这个公布也是可以有选择性的公布给其它对象。在java中能使用private、protected、public三种修饰符或不用(即默认defalut)对外部对象访问该对象的属性和行为进行限制。

继承:是子对象可以继承父对象的属性和行为,亦即父对象拥有的属性和行为,其子对象也就拥有了这些属性和行为。这非常类似大自然中的物种遗传。

多态:不是很好解释,更倾向于使用java中的固定用法,即overriding(覆盖)和overload(过载)。多态则是体现在overriding(覆盖)上,而overload(过载)则不属于面向对象中多态的范畴,因为overload(过载)概念在非面向对象中也存在。overriding(覆盖)是面向对象中的多态,因为overriding(覆盖)是与继承紧密联系,是面向对象所特有的。多态是指父对象中的同一个行为能在其多个子对象中有不同的表现。也就是说子对象可以使用重写父对象中的行为,使其拥有不同于父对象和其它子对象的表现,这就是overriding(覆盖)。

17.Override和Overload的含义去区别。

方法的重写(Overrid)和重载(Overload)是Java多态性的不同表现。

重写(Overriding)是父类与子类之间多态性的一种表现,而重载(Overload)是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overrid) 。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被"屏蔽"了。如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型或有不同的参数次序,则称为方法的重载(Overload)。不能通过访问权限、返回类型、抛出的异常进行重载。

1. Override 特点

1、覆盖的方法的标志必须要和被覆盖的方法的标志完全匹配,才能达到覆盖的效果;

2、覆盖的方法的返回值必须和被覆盖的方法的返回一致;

3、覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类;

4、方法被定义为final不能被重写。

5、对于继承来说,如果某一方法在父类中是访问权限是private,那么就不能在子类对其进行重写覆盖,如果定义的话,也只是定义了一个新方法,而不会达到重写覆盖的效果。(通常存在于父类和子类之间。)

2.Overload 特点

1、在使用重载时只能通过不同的参数样式。例如,不同的参数类型,不同的参数个数,不同的参数顺序(当然,同一方法内的几个参数类型必须不一样,例如可以是fun(int, float), 但是不能为fun(int, int));

2、不能通过访问权限、返回类型、抛出的异常进行重载;

3、方法的异常类型和数目不会对重载造成影响;

4、重载事件通常发生在同一个类中,不同方法之间的现象。

5、存在于同一类中,但是只有虚方法和抽象方法才能被覆写。

18.Interface与abstract类的区别。

对于抽象类:

1、抽象类不能被实例化,实例化的工作应该交由它的子类来完成,它只需要有一个引用即可。

2、抽象方法必须由子类来进行重写。

3、只要包含一个抽象方法的抽象类,该方法必须要定义成抽象类,不管是否还包含有其他方法。

4、抽象类中可以包含具体的方法,当然也可以不包含抽象方法。

5、子类中的抽象方法不能与父类的抽象方法同名。

6、abstract不能与final并列修饰同一个类。

7、abstract 不能与private、static、final或native并列修饰同一个方法。

对于接口:

1、1个Interface的方所有法访问权限自动被声明为public。确切的说只能为public,当然你可以显示的声明为protected、private,但是编译会出错!

2、接口中可以定义“成员变量”,或者说是不可变的常量,因为接口中的“成员变量”会自动变为为public static final。可以通过类命名直接访问:ImplementClass.name。

3、接口中不存在实现的方法。

4、实现接口的非抽象类必须要实现该接口的所有方法。抽象类可以不用实现。

5、不能使用new操作符实例化一个接口,但可以声明一个接口变量,该变量必须引用(refer to)一个实现该接口的类的对象。可以使用 instanceof 检查一个对象是否实现了某个特定的接口。例如:if(anObject instanceof Comparable){}。

6、在实现多接口的时候一定要避免方法名的重复。

19.Static class 与non static class的区别。

static与non-static是对立的。static应当(注意是应当)使用类名来引用。而non-static必须(是必须)使用对象实例名来引用。

static与non-static在引用数据成员方面的差别:因为static、non-static的数据相关性,static只能引用类的static数据成员;而non-static既可以引用类的static数据成员,也可以引用对象自身的数据。

static与non-static method在overload方面是一样的。

而static与non-static method在override方面则完全不同。static方法是与类相关的,不是通过this引用的,所以它不能被override。其引用在编译期就得确定。而non-static方法才有可能被override。

static与abstract,它们不能同时用于修饰一个方法。因为abstract的语义就是说这个方法是多态方法,需要subclass的实现。而static方法则是在本类中实现的,编译期绑定,不具有多态行为。

20.java多态的实现原理。

参考jvm虚拟机的动态绑定和静态绑定:参考资料

21.实现多线程的两种方法:Thread与Runable。

1.继承Thread类实现Runable接口,然后new Thread(Runable r).start();

2.new Thread(){public void run(){}}.start();  //匿名内部类

22.线程同步的方法:sychronized、lock、reentrantLock等。

具体参考:参考资料

23.锁的等级:方法锁、对象锁、类锁。

对象锁(方法锁),是针对一个对象的,它只在该对象的某个内存位置声明一个标识该对象是否拥有锁,所有它只会锁住当前的对象,一般一个对象锁是对一个非静态成员变量进行synchronized修饰,或者对一个非静态成员方法进行synchronized进行修饰,对于对象锁,不同对象访问同一个被synchronized修饰的方法的时候不会阻塞

类锁是锁住整个类,当有多个线程来声明这个类的对象时候将会被阻塞,直到拥有这个类锁的对象呗销毁或者主动释放了类锁,这个时候在被阻塞的线程被挑选出一个占有该类锁,声明该类的对象。其他线程继续被阻塞住。

无论是类锁还是对象锁,父类和子类之间是否阻塞没有直接关系。当对一个父类加了类锁,子类是不会受到影响的,相反也是如此。因为synchronized关键字并不是方法签名的一部分,它是对方法进行修饰的。当子类覆写父类中的同步方法或是接口中声明的同步方法的时候,synchronized修饰符是不会被自动继承的,所以相应的阻塞问题不会出现。

24.写出生产者消费者模式。

参考:生产者消费者模式

25.ThreadLocal的设计理念与作用

Java中的ThreadLocal类允许我们创建只能被同一个线程读写的变量。因此,如果一段代码含有一个ThreadLocal变量的引用,即使两个线程同时执行这段代码,它们也无法访问到对方的ThreadLocal变量。

作用:Thread是隔离多个线程的数据共享

26.ThreadPool用法与优势

合理利用线程池能带来三个好处:

1.降低资源消耗。通过重复利用已创建的线程降低线程的创建与销毁所造成的消耗。

2.提高相应速度。当任务到达时,不需要等到线程创建就能立即执行。

3.提高线程的可管理性。线程是稀缺资源,如果无限制创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池会对线程进行统一的分配,调优和监控。

27.Concurrent包里的其他东西:ArrayBlockingQueue、CountDownLatch等等。

28.wait()和sleep()的区别

wait()方法是object类的方法,sleep()方法是Thread类的方法。由于sleep()方法是Thread类的方法,因此它不能改变对象的机锁。所以当在一个Synchronized方法中调用sleep()时,线程虽然休眠了,但是对象的机锁没有被释放,其他线程仍然无法访问这个对象。而wait()方法则会在线程休眠的同时释放掉机锁,其他线程可以访问该对象。当一个线程执行到wait()方法时(线程休眠且释放机锁),它就进入到一个和该对象相关的等待池中,同时失去了对象的机锁。当它被一个notify()方法唤醒时,等待池中的线程就被放到了锁池中。该线程从锁池中获得机锁,然后回到wait()前的中断现场。

29.foreach与正常for循环效率对比

循环ArrayList时,普通for循环比foreach循环花费的时间要少一点;循环LinkList时,普通for循环比foreach循环花费的时间要多很多。

需要循环数组结构的数据时,建议使用普通for循环,因为for循环采用下标访问,对于数组结构的数据来说,采用下标访问比较好。需要循环链表结构的数据时,一定不要使用普通for循环,这种做法很糟糕,数据量大的时候有可能会导致系统崩溃。

30.Java IO与NIO。

31.反射的作用于原理

所谓反射是JAVA 语言允许在 运行时拥有一种自审的能力,也就是说JVM 允许代码在运行期间可以获得类的内部信息,并能直接操作程序的内部属性和方法。具体请看:参考资料

32.泛型常用特点,List能否转为List

在Java的泛型接口中 把List < String > 转换成List < Object >  是可以,也是可以运行的。

33.解析XML的几种方式的原理与特点:DOM、SAX、PULL。

DOM的特点

优点

1.整个文档树在内存中,便于操作;支持删除、修改、重新排列等多种功能

2.通过树形结构存取xml文档

3.可以在树的某个节点上向前或向后移动

缺点

1.将整个文档调入内存(包括无用的节点),浪费时间和空间

适用场合

一旦解析了文档还需多次访问这些数据;硬件资源充足(内存,cpu)

DOM解析步骤

1.创建解析器工厂

2.获得解析器工厂

3.接受一个xml文档作为输入参数名,并得到一个xml的文档对象(Document)

4.操作文档对象

Sax特点

1. 解析效率高,占用内存少

2.可以随时停止解析

3.不能载入整个文档到内存

4.不能写入xml

5.SAX解析xml文件采用的是事件驱动

---sax并不需要解析完 整个文档,在按内容顺序解析文档的过程中,sax会判断当前读到的字符是否合法xml语法中的某部分,如果符合就会触发事件

Sax工作原理

Sax的工作原理简单的说,就是对文档进行顺序扫描,扫描到文档(document)开始与结束,扫描到元素(element)开始、结束等地方时调用事件处理

处理函数做相应动作,然后继续扫描,直到文档结束。

Sax解析文档过程

1.继承DefaultHandler  ,并实现方法

2.创建SAX解析器工厂

3.获得解析器

4.获得输入流

5.使用输入流,和实现接口作参数,调用解析器的解析方法进行解析

pull解析器简介

1.pull解析器是android内置的解析器,解析原理与sax类似

2.pull它提供了类似的事件。

如:开始元素和结束元素事件,使用parse.next()可以进入下一个元素并触发相应的事件,事件将作为数值代码被发送

因此可以使用一个switch对感兴趣的事件进行处理。当元素开始解析时,调用parser.nextText()方法获取下一个Text类型节点的值

pull与sax的不同之处

1.pull读取xml文件后触发相应的事件调用方法返回的是数字。

2.pull可以在程序中控制,想解析到哪里就可以停止到哪里

3.Android中更推荐使用pull解析

pull解析步骤

1.创建解析器对象

XmlPullParser paser = Xml.newPullParser();

2.进行解析

paser.setInput(input,"utf-8");

3.产生第一个解析事件

int eventType = paser.getEventType();

4.可以使用循环判断是否继续解析

while(eventType!=XmlPullParser.END_DOCUMENT){}

详细解析:参阅资料

34.Java与C++对比。

1. C++不会在运行时检验数组是否越界,没有垃圾回收机制

2.C++没有为所有的类提供一个可以从中继承出来的一般类object。

3.Qt则为所有的类型提供了一个简单的基类

4.Java中的“接口”的概念,只能用C++的纯虚函数来表示

5.C++不允许在类定义中初始化成员变量

6.C++中没有能够只想基类的super关键字,如需调用,可以在这个函数的名字前加一个由基类的名字和“::”操作符构成的前缀

7.C++支持多重继承,一个类可以同时从多个类中派生出来

35.Java1.7与1.8新特性

1.7:

1.二进制变量的表示,支持将整数类型用二进制来表示,用0b开头

2.Switch语句支持string类型

3.数字类型的下划线表示 更友好的表示方式,好看好分辨

4.创建泛型时类型判断

1.8:

支持lamda表达式

36.设计模式:单例、工厂、适配器、责任链、观察者等等

具体请下载文档查看:24种设计模式介绍与6大设计原则.pdf

37.JNI的使用

1.编写带有native方法的java类。使用javac方法编译java类

2.使用javah来生成与native方法对应的头文件

3.实现相应的头文件,并编译成动态链接库


注:以上内容大部分来源于网络,可能有不准确的地方,希望大家指出,我汇认真修改哒。

你可能感兴趣的:(J2SE基础)