注意:不支持long,double,JDK7之后,开始支持String。
//简单示例 publicclassMyDemo{ publicstaticvoidmain(String... args){ Demo demo = Demo.A; switch(demo) { caseA: break; caseB: break; } } enumDemo { A, B, C } }
对于几个固定值的判断,建议使用switch语句,因为switch语句会将具体的答案加载进内存,相对高效一点。
饿汉式
privatestaticSingle s =newSingle ( ); privateSingle( ){ } publicstaticSinglegetInstance() { returns ; } }
懒汉式
classSingle{ publicstaticSinglegetInstance(){ if( s==null){ synchronized(Single.class){//锁不读可以提高效率 if( s==null){ s = newSingle () ; } } returns ; } }
(关于问题1,谢谢 ylt 提醒)
try{ }catch(){ }finally{}
在catch中return(),finally{}会不会执行?
答:会,会在return之后执行。
finally()在什么情况下不会执行
答:只有一种情况不会执行,当执行到System.exit(0)时,finally不会执行。
publicclassTest{ publicstaticvoidmain(String[] args){ System.out.println("haha:"+ haha(true)); } privatestaticbooleanhaha(booleanisTrue){ try{ inti =1/0; returnisTrue ? System.out.printf("return try !null ","test") !=null: System.out.printf("return try null ","test") ==null; } catch(Exception e) { System.out.println("catch"); returnisTrue ? System.out.printf("return catch !null ","test") !=null: System.out.printf("return catch null ","test") ==null; } finally{ System.out.println(""); System.out.println("finally"); } } }
//打印结果: catch returncatch!null finally haha:true
ArithmeticException, ClassCastException, IllegalArgumentException, IndexOutOfBoundsException, NullPointerException,
先看下面一段代码,运行Test,会打印什么?
package test; publicclassTest{ publicstaticvoidmain(String... args){ TestA a; a = newTestA(); a = newTestA(); TestA aa = newTestA(); } } classTestA{ { System.out.println("TestA code create"); } privateTestB b =newTestB(); privatestaticTestC c =newTestC(); publicTestA(){ System.out.println("TestA create"); } static{ System.out.println("TestA static create"); } } classTestB{ publicTestB(){ System.out.println("TestB create"); } } classTestC{ publicTestC(){ System.out.println("TestC create"); } }
打印结果:
TestC create TestA staticcreate TestA code create TestB create TestA create TestA code create TestB create TestA create TestA code create TestB create TestA create
作用:给对象进行初始化,对象一建立就运行,而且优先于构造函数执行。
和构造函数的区别:
static{ 静态代码块中的执行语句; } 特点:随着类的加载而执行,只执行一次(再new一个对象也不会执行,类只加载一次), 如果定义在有主函数的类中,则优先于主函数执行。用于给类进行初始化。 有些类不用创建对象,无法用构造函数初始化,就通过静态代码块初始化。 执行顺序:静态代码块先执行,如果有对象,构造代码块先执行,然后是构造函数。 如果没有对象,则构造代码块和构造函数都不会执行。
因为接口没有方法体,不会存在两个父类出现同一个方法但是方法体不同的情况,不会引起冲突,如下:
publicclassTestimplementsd{ publicstaticvoidmain(String... args){ } @Override publicvoidas(){ } } interfacedextendse,f{ } interfacef{ voidas(); } interfacee{ voidas(); }
相同点:都是不断向上抽取而来的。不可以被实例化
不同点:
子类的实例化过程:
结论:子类的所有的构造函数,默认都会访问父类中空参数构造函数,因为子类中每一个构造函数内的第一行都有一句隐式的super() ;
当父类中没有空参数的构造函数时,子类必须手动通过super或者this语句形式来指定要访问的构造函数。
当然:子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数,
子类中至少会有一个构造函数会访问到父类中的构造函数。
见下图:
打印结果:
关于线程这块,后期有时间会写一个完整的深入的文章,这里写的都是比较简单基础的线程的一些知识。
创建线程的两种方式:
继承Thread类。
实现Runnable接口
实现方式相比继承方式的好处:
避免了单继承的局限性(单继承只能继承一个父类)。在定义线程时,建议使用实现方式。
存放代码的位置不一样:
继承Thread:线程代码存放Thread子类的run方法中
实现Runnable,线程代码存在接口的子类的run方法。
将线程的任务从线程的子类中分离出来,进行了单独的封装。按照面向对象的思想将任务的封装成对象。
避免了java单继承的局限性。
同步代码块
synchronized(对象){ 需要被同步的代码; }
同步函数。
将synchronized关键字作为修饰符放在函数上。
public synchronized void add()
同步函数用的是哪一个锁:函数需要被对象调用,那么该函数都有一个所属对象引用,就是this,所以同步函数使用的锁是this(对象)
JDK1.5中提供了多线程升级解决方案,将同步synchronized替换成实现Lock操作,将Object中的wait,notify,notifyAll,替换成了Condition对象的await(),signal(),signalAll(),该对象可以通过Lock锁进行获取。
* 停止线程 原理:run方法结束 1. 使用intrrupt()方法。该方法是结束线程的冻结状态,使线程回到运行状态中来。 当线程处于冻结状态,就不会结束读取到标记,那么线程就不会结束。 当没有指定的方式让冻结的线程恢复到运行状态时,这时需要对冻结进行清除。 强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束。 2. 定义循环结束标记。线程运行代码一般都是循环,只要控制了循环即可。 * 线程常见方法 ```cs 1 setDeamon() 守护线程:setDaemon(ture) ; 也称后台线程,当前台线程执行时后台线程也在执行,但是当前台线程全部执行完关闭时, 后台线程也会跟着自动关闭,jvm退出。 !!该方法必须在启动线程前调用。 2 join()等待该线程终止:一般用于临时加入线程。 当A线程执行到了B线程的.join()方法时,A就会等待,等B线程都执行完,A才会执行 3 yield()方法:释放执行权,让其他线程运行。 暂停当前正在执行的线程对象,并执行其他线程。
一个死锁的 demo
classTestimplementsRunnable{ privatebooleanflag; Test(booleanflag) { this.flag = flag; } publicvoidrun(){ if(flag) { while(true) synchronized(MyLock.locka) { System.out.println(Thread.currentThread().getName() + "..if locka...."); synchronized(MyLock.lockb) { System.out.println(Thread.currentThread().getName() + "..if lockb...."); } } } else{ while(true) synchronized(MyLock.lockb) { System.out.println(Thread.currentThread().getName() + "..else lockb...."); synchronized(MyLock.locka) { System.out.println(Thread.currentThread().getName() + "..else locka...."); } } } } } classMyLock{ publicstaticfinalObject locka =newObject(); publicstaticfinalObject lockb =newObject(); } classDeadLockTest{ publicstaticvoidmain(String[] args){ Test a = newTest(true); Test b = newTest(false); Thread t1 = newThread(a); Thread t2 = newThread(b); t1.start(); t2.start(); } }
wait和sleep的区别
1.wait可以指定时间也可以不指定。sleep必须指定时间。 2. 在同步中,对CPU的执行权和锁的处理不同: wait:释放执行权,释放锁 sleep:释放执行权,不释放锁
StringBuffer和StringBuilder的区别
StringBuffer是线程同步(安全)。如果是单线程,效率就比较低
StringBuilder是线程不同步。
List 和 set
List:元素是有序的,元素可以重复,因为该集合体系有索引 Set:元素是无序的,元素不可以重复(存入和取出的顺序不一定一致)。 List特有方法:凡是可以操作角标的方法都是该体系特有的方法
List中常见的三个子类
LinkedList
JDK1.6版本出现的:pollFirst(),pollLast(),peekFirst() ,peekLast(),offerFirst(),offerLast() (如果链表为空,返回null)。 分别替代了remove和get和add(如果链表为空,则抛出异常)。
set常见子类
1. HashSet:底层数据结构是哈希表。 HashSet是如何保证元素的唯一性的: 是通过元素的两个方法,hashCode和equals来完成,如果元素的hashCode值相同, 才会判断equals是否为true,如果元素的hashCode值不同,不会调用equals 。 开发时描述事物,需要往集合里面存时,一般都要复写hashCode和equals。
TreeSet底层的数据结构:二叉树
保证数据元素唯一性的依据compareTo方法return 0,为0则表示是相同元素 ;
排序的两种方式: TreeSet排序的第一种方式: 让元素自身具备比较性。元素需要实现Comparable接口,覆盖compareTo方法。这种方式也称为元素的自然顺序,或者叫做默认顺序。 TreeSet的第二种排序方式: 当元素自身不具备比较性时,或具备的比较性不是所需要的,这是就需要让集合自身具备比较性。 定义一个比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。 定义一个类,实现Comparator接口,覆盖compare方法 当两种排序都存在时,以比较器为主。
泛型技术是给编译器使用的技术,用于编译时期。确保了类型的安全。
运行时,会将泛型去掉,生成的class文件中是不带泛型的,这个称为泛型的擦除。
为什么擦除呢?因为为了兼容运行的类加载器。
泛型的补偿:在类加载器原有基础上,编写一个补偿程序。在运行时,通过反射,
获取元素的类型进行转换动作。不用使用者在强制转换了。
常见子类
Hashtable:底层是哈希表数据结构,不可以存入null键null值,该集合是线程同步的。jdk1.0,效率低 。 HashMap:底层是哈希表数据结构,并允许使用null键null值,该集合不是同步的,jdk1.2,效率高。 TreeMap :底层是二叉树数据结构,线程不同步,可以给map集合中的键进行排序 。 Map和Set很像 :其实,Set底层使用了Map集合 。
map集合的两种取出方式:
1.Set<K> KeySet: 将Map中所有的Key存到了Set集合中,因为Set集合具备迭代器。 所有可以迭代方式取出所有的键,再根据get方法,获取每一个键对应的值 Map集合的取出原理:将Map集合转成Set集合,再通过迭代器取出 2.Set<Map.Entry<K,V>> entrySet:将Map集合中的映射关系存入到了Set集合中,而这个关系的数据类型就是:Map.Entry。 Map.Entry :其实Entry也是一个接口,它是Map接口中的一个内部接口。 先有Map,才有映射关系,所有Entry类定义在Map内部
Math类:
doubled = Math.ceil(12.56);// 13.0 。ceil返回大于指定整数的最小整数 doubled1 =Math.floor(12.34);//12.0 。floor返回小于指定数据的最大整数 longl = Math.round(12.64);//四舍五入 doubled2 = Math.pow(2,3);//幂运算 :2^3 = 8
字节流:InputStream(读) OutputStream(写)
RandomAccessFile(断点下载会用到的类):
随机访问文件,自身具备读写的方法。
通过skipBytes(int x),seek(int x)来达到随机访问。
seek(int x):调整对象中指针,指针跳转,可以实现对数据指定位置的读取和写入。
IO流体系:
字符流: Reader |--BufferedReader: |--LineNumberReader |--CharArrayReader |--StringReader |--InputStreamReaer |--FileReader Writer |--BufferedWriter |--CharArrayWriter |--StringWriter |--OutputStreamWriter |--FileWriter |--PrintWriter 字节流: InputStream |--FileInputStream: |--FilterInputStream |--BufferedInputStream |--DataInputStream |--ByteArrayInputStream |--ObjectInputStream |--SequenceInputStream |--PipedInputStream OutputStream |--FileOutputStream |--FilterOutputStream |--BufferedOutputStream |--DataOutputStream |--ByteArrayOutputStream |--ObjectOutputStream |--PipedOutputStream |--PrintStream
示例:读出C盘下txt文件
publicstaticvoidlistDemo_2(){ File dir = newFile("c://"); String[] names = dir.list(newSuffixFilter(".txt")); for(String name : names){ System.out.println(name); } } publicclassSuffixFilterimplementsFilenameFilter{ privateString suffix ; publicSuffixFilter(String suffix){ super(); this.suffix = suffix; } @Override publicbooleanaccept(File dir, String name){ returnname.endsWith(suffix); } }
示例:深度递归,读出制定目录下的所有文件和文件夹,包括子目录。
publicclassFileTest{ publicstaticvoidmain(String[] args){ File dir = newFile("D://me//mime//RuntimePermissions"); listAll(dir,0); } /** * * @paramdir * @paramspaceLevel 这个是为了打印结果好看,与空格有关的参数 */ publicstaticvoidlistAll(File dir,intspaceLevel){ System.out.println(getSpace(spaceLevel)+dir.getName()); //获取指定目录下当前的所有文件夹或者文件对象 spaceLevel++; File[] files = dir.listFiles(); for(intx=0; x<files.length; x++){ if(files[x].isDirectory()){ listAll(files[x],spaceLevel); } else System.out.println(getSpace(spaceLevel)+files[x].getName()); } } privatestaticStringgetSpace(intspaceLevel){ StringBuilder builder = newStringBuilder(); builder.append("|--"); for(intx=0; x<spaceLevel; x++){ builder.insert(0,"| "); } returnbuilder.toString(); } }