子類應該比 父類更爲 開放 (public protected default private) 子類方法不能比父類拋出更高異常( 能夠爲父類方法異常自己或者其異常的子類) 關於類加載和初始化相關的案例 總的順序是:先父類後子類,先靜態後動態,屬性和代碼塊的初始化遵循正常的出場順序不管是靜態仍是動態,可是他們老是先於構造器執行。可是仍是須要經過題目的學習來加深咱們的理解。 package ooptest; public class StaticDemo6 { public static void main(String[] args) { new SB(); } } class SA { D d; static { System.out.println("A 1"); // 1.先從父類的靜態開始 } { System.out.println("A 2"); // 5.此處開始new對象(非靜態相關) d = new D();// 6.順序執行 } public SA() { System.out.println("A 3"); // 10.此時調用完了本身的非靜態代碼塊來到了構造器 } } class SB extends SA { static C c = new C(); // 2.調用完了父類的靜態相關來到子類的靜態相關 static { System.out.println("B 1"); // 4.接着按照順序來調用本身的靜態代碼塊 ,到此子類的全部靜態都執行完畢接下來將會執行非靜態相關 } { System.out.println("B 2"); // 11.父類的構造器調用完成調用子類的非靜態塊 } public SB() { System.out.println("B 3"); // 12.調用完了本身的非靜態塊調用本身的構造方法 } } class C { public C() { System.out.println("C"); // 3.C沒有父類與靜態直接調用本身的構造器 // 8. } } class D extends C {// 7. 來到了D可是D有本身的父類因此到達C類 public D() { System.out.println("D");// 9.調用完了父類的構造器會來到子類的構造器 } } package com.ghc.mmall.concurrency.test; class ClassA { public static ClassA classa = new ClassA(); static{ System.out.println("ClassA的靜態代碼塊"); } public ClassA(){ System.out.println("ClassA的構造方法"); } { System.out.println("ClassA的構造代碼塊"); } } class ClassB extends ClassA{ static{ System.out.println("ClassB的靜態代碼塊"); } public ClassB(){ System.out.println("ClassB的構造方法"); } { System.out.println("ClassB的構造代碼塊"); } public static ClassC classc = new ClassC(); public void excute(){ System.out.println("執行方法"); } } class ClassC { public ClassC(){ System.out.println("ClassC的構造方法"); } } public class Test { static { System.out.println("Test的靜態代碼塊"); } public static void main(String[] args) { System.out.println("執行main方法"); ClassB b = new ClassB(); b.excute(); } } 能夠單步調試 看輸出打印結果 Test的靜態代碼塊 執行main方法 ClassA的構造代碼塊 ClassA的構造方法 ClassA的靜態代碼塊 ClassB的靜態代碼塊 ClassC的構造方法 ClassA的構造代碼塊 ClassA的構造方法 ClassB的構造代碼塊 ClassB的構造方法 執行方法 深度加載知識 不管如何類的加載都 ①先進行解析(也就是聲明靜態變量可是不去初始化),也就是將靜態變量放入方法區而且標記,標記一個值0。至關於只定義沒有賦值。 ②當全部的解析都過去的時候才進行初始化,初始化就是按照出場順序來執行靜態代碼塊和檢查靜態變量那裏是否賦值值,若是有值得話那麼就賦值,沒有的話那麼就將標記值賦值給靜態變量。 注意:標記狀態的值至關於無值它不能夠直接參加運算可是能夠間接的使用標記的值。類名調用。 class Demo { public static void main(String[] args) { System.out.println(Demo.i); } static { i = 7; // 1 } static int i; // 2 } 結果是 7
若是沒有定義環境變量classpath,java啓動jvm後,會在當前目錄下查找要運行的類文件; 若是指定了classpath,那麼會在指定的目錄下查找要運行的類文件。 還會在當前目錄找嗎?兩種狀況: 1):若是classpath的值結尾處有分號,在具體路徑中沒有找到運行的類,會默認在當前目錄再找一次。 2):若是classpath的值結果出沒有分號,在具體的路徑中沒有找到運行的類,不會再當前目錄找。 通常不指定分號,若是沒有在指定目錄下找到要運行的類文件,就報錯,這樣能夠調試程序。 **級別從低到高爲:**byte,char,short(這三個平級)–>int–>float–>long–>double Java語言規範建議按如下順序列出修飾符: 1. Annotations 2. public 3. protected 4. private 5. abstract 6. static 7. final 8. transient 9. volatile 10. synchronized 11. native 12. strictfp
// 短路與非短路 驗證 public class Hello { public static boolean compare(int n1, int n2){ System.out.println(n1+" --> "+n2); return n1>n2; } public static void main(String [] args){ System.out.println(compare(2,3) & compare(4,3)); // 非短路 System.out.println(compare(2,3) && compare(4,3)); // 短路 } }
package com.ghc.test; import java.security.SecureRandom; import java.util.Random; import java.util.logging.Logger; import java.util.logging.Level; public class Test { private static final Logger logger = Logger.getGlobal(); public static void main(String [] args){ logger.info("start log info..."); double res = getRand(1,10); double res2 = getRand2(11,20); System.out.println(res2); double secureRes = getSecureRand(20,30); System.out.println(secureRes); } public static double getRand(long min, long max){ long gap = max - min; return (long)(Math.random() * gap + min); } public static double getRand2(int min, int max){ final Random random = new Random();// 默認種子值爲 時間戳 int randInt = random.nextInt(max); double res = randInt<min?randInt+min:randInt; return res; } public static double getSecureRand(int min, int max){ SecureRandom secureRandom = new SecureRandom(); int randInt = secureRandom.nextInt(max); int res = randInt<min?randInt+min:randInt; return res; } }
String s = new String(new char[]{'h','e','l','l'}); System.out.println(s.hashCode()); // 3198781 String s2 = s.toUpperCase(); System.out.println(s2.hashCode()); // 2213693 System.out.println(s == s2); // false System.out.println(s.equalsIgnoreCase(s2)); //true 從表面上看,兩個字符串用==和equals()比較都爲true,但實際上那只是Java編譯器在編譯期, 會自動把全部相同的字符串看成一個對象放入常量池,天然s1和s2的引用就是相同的。 String 的 getBytes 方法 等同於 python 的 encoding , 而 new String("中文","UTF-8") 就是 decode 了
在 開發階段不須要引入 Log4j , 儘管 Log4j 是最流行的日誌框架,可是使用 commons logging 可以很是容易地切換日誌框架 import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; 只有當咱們要對 log4j 的接口進行擴展時候才須要引入 log4j ,不然 使用 commons logging 足矣 import org.apache.log4j.Logger;
泛型通常應用於 集合類型中,若是咱們不使用泛型則會變成 Object ,在源碼編寫時候須要強轉,雖然編譯後泛型也會被擦除,可是在源碼編寫時後咱們不須要強轉 E — Element,經常使用在java Collection裏,如: List<E>,Iterator<E>,Set<E> K,V — Key,Value,表明Map的鍵值對 N — Number,數字 T — Type,類型,如String,Integer等等 // 由於泛型在編譯後就會被擦除, 因此沒法被直接實例化 class GenericsA<T> { T t = new T(); // Error } type erasure 泛型擦拭 ,全部泛型最終在編譯器內都認爲是 Object ,因此基本數據類型不能用做泛型,編譯後的字節碼中不包含任何泛型信息是 Object 而後 (String) obj 這樣強轉 因此咱們也不能用 p isinstanceof Pair<Integer>.class 或者 用 new T() 這樣的方式來編碼。
package com.ghc.test; import org.junit.Test; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; public class Pair <T extends Number> { private T first; private T last; Pair(T first, T last){ this.first = first; this.last = last; } public Pair(){super();} public void setFirst(T first){ this.first = first; } public void setLast(T last){ this.last = last; } public T getFirst(){ return this.first; } public T getLast(){ return this.last; } public static <K extends Number> Pair createPair(K k1, K k2){ return new Pair<K>(k1,k2); } @Override public String toString(){ return "Pair("+this.getFirst()+","+this.getLast(); } @Test public void test(){ Pair<Integer> integerPair = new Pair<>(1,2); Pair<Float> floatPair = new Pair<>(1f,2f); System.out.println(integerPair.getFirst()); System.out.println(integerPair.getClass() == Pair.class); System.out.println(floatPair.getClass() == Pair.class); // 反射 獲取 父類泛型 Class<IntegerPair> clazz = IntegerPair.class; Type t = clazz.getGenericSuperclass(); if(t instanceof ParameterizedType){ ParameterizedType parameterizedType = (ParameterizedType) t; Type [] types = parameterizedType.getActualTypeArguments(); for(Type type:types){ System.out.println(type.getTypeName()); } } String[] results = getSuperClassGenericType(IntegerPair.class); for(String res:results){ System.out.println(res); } } public static<C> String [] getSuperClassGenericType(Class<C> clazz){ Type superType = clazz.getGenericSuperclass(); List<String> typesStrList = new ArrayList<>(1); if(superType instanceof ParameterizedType){ Type[] types = ((ParameterizedType) superType).getActualTypeArguments(); for(Type type:types){ typesStrList.add(type.getTypeName()); } } String [] results = new String[typesStrList.size()]; return typesStrList.toArray(results); } } class IntegerPair extends Pair<Integer>{ } // 調用時候 修改方法簽名 ? extends Number class PairHelper{ static int add(Pair<? extends Number> p){ // 在 get 時候 能夠變得靈活易用 Number first = p.getFirst(); Number last = p.getLast(); // p.setFirst(first); extends 上界通配符 容許調用 get 方法,卻不容許 調用 set 方法 除了 null return first.intValue() + last.intValue(); } /* static int add(Pair<? super Integer> p){ // 這樣 泛型擦除後 就會 是一樣的函數了 }*/ static void set_super(Pair<? super Integer> p){ // 在 set 時候 能夠 變得靈活易用 //Integer integer = p.getFirst(); // 下邊界的 泛型 沒法使用 get 僅僅能夠用 Object 接收 可使用 set 具體緣由看函數簽名 Object integer = p.getFirst(); /*Incompatible types. Required: java.lang.Integer Found: capture<? super java.lang.Integer>*/ p.setFirst(Integer.valueOf(2));// Integer 的超類確定能夠接收一個 Integer 對象 } } // 最後來一個綜合例子 就能夠理解 了 class MyCollections{ public static <T> void copy(List<? extends T> src , List<? super T> dest){ for(T t:src){ dest.add(t); } } }
public enum WeekDayEnum { MONDAY("monday",1), TUESDAY("tuesday",2), WEDNESDAY("Wednesday",3), THURSDAY("thursday",4), FRIDAY("friday",5); private String dayName; private int id; // 枚舉類構造方法必須聲明爲 private private WeekDayEnum(String dayName, int id){ this.dayName = dayName; this.id = id; } public String getDayName(){ return this.dayName; } } WeekDayEnum enum1 = WeekDayEnum.WEDNESDAY; switch(enum1){ case MONDAY: case TUESDAY: case WEDNESDAY: case THURSDAY: case FRIDAY: System.out.println("weekday -> "+enum1.getDayName()); break; default:System.out.println("weekend"); } 利用 name() 方法獲取常量定義的字符串 而不要使用 toString 方法由於 toString 能夠被複寫
JAVA 註解全接觸java
註解準備知識:看到一個註解的源碼 @Target 使用註解時的做用的目標 ElementType.ANNOTATION_TYPE 能夠【給一個註解進行註解】 ElementType.CONSTRUCTOR 能夠給構造方法進行註解 ElementType.FIELD 能夠給屬性進行註解 ElementType.LOCAL_VARIABLE 能夠給局部變量進行註解 ElementType.METHOD 能夠給方法進行註解 ElementType.PACKAGE 能夠給一個包進行註解 ElementType.PARAMETER 能夠給一個方法內的參數進行註解 ElementType.TYPE 能夠給一個類型進行註解,好比類、接口、枚舉 @Retention 註解生效的做用域 RetentionPolicy.SOURCE 註解只在源碼階段保留,在編譯器進行編譯時它將被丟棄忽視。 RetentionPolicy.CLASS 註解只被保留到編譯進行的時候,它並不會被加載到 JVM 中。 RetentionPolicy.RUNTIME 註解能夠保留到程序運行的時候,它會被加載進入到 JVM 中,因此在程序運行時能夠獲取到它們。 @Documented 這個元註解確定是和文檔有關。它的做用是可以將註解中的元素包含到 Javadoc 中去 @Inherited 代表該註解若是註解了父類,那麼子類就會繼承這些註解(即便子類沒有被任何註解) @Repeatable 代表該註解能夠在同一目標上屢次使用,就像能夠貼多個標籤 @AliasFor 註解屬性的別名 (給註解的這個屬性賦值就等於給AliasFor的這個屬性賦值) 註解能夠有多個屬性,沒有指明key的,會【默認給註解屬性的value()賦值】
Table 註解python
import java.lang.annotation.*; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface Table { String value(); }
Column 註解android
import java.lang.annotation.*; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface Column { String value(); }
Filter 類裏 使用註解web
package com.ghc.hbase.api; @Table("user") public class Filter { @Column("id") private int id; @Column("userName") private String userName; @Column("nickName") private String nickName; @Column("age") private int age; @Column("city") private String city; @Column("email") private String email; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getNickName() { return nickName; } public void setNickName(String nickName) { this.nickName = nickName; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
package com.ghc.hbase.api; import java.lang.reflect.Field; import java.lang.reflect.Method; public class Test { public static void main(String [] args) throws Exception{ Filter filter1 = new Filter(); filter1.setAge(18); filter1.setCity("ny"); filter1.setEmail("test@gmail.com"); filter1.setId(666); filter1.setUserName("Frank"); filter1.setNickName("Rocket"); System.out.println(query(filter1)); } public static String query(Filter filter) throws Exception{ Class clazz = filter.getClass(); Table table = (Table)clazz.getAnnotation(Table.class); String tableName = table.value(); StringBuilder sb = new StringBuilder(); sb.append("select * from ") .append(tableName) .append(" where 1=1 "); Field [] fields = clazz.getDeclaredFields(); Method [] methods = clazz.getDeclaredMethods(); for(Field field:fields){ Object obj = null; Column column = (Column)field.getAnnotation(Column.class); for(Method method:methods){ // System.out.println(field.getName() + "---> "+ method.getName()); String fieldName = field.getName(); if(("get"+ fieldName).equalsIgnoreCase(method.getName())){ obj = method.invoke(filter,null) ; String value = obj instanceof String?"\""+obj+"\"":String.valueOf(obj); sb.append(" and "+column.value()+"="+value); } } } return sb.toString(); } }
package com.ghc.concurrence.ConcurrentPractice; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; public class ThreadPoolPractice { private static int threadTotal = 200; private static int clientTotal = 5000; private static int count = 0; public static void main(String [] args){ ExecutorService executorService = Executors.newCachedThreadPool(); final Semaphore semaphore = new Semaphore(threadTotal); for(int i=0;i<clientTotal;i++){ executorService.execute(()->{ try{ semaphore.acquire(); add(); semaphore.release(); }catch(Exception e){ e.printStackTrace(); } }); } executorService.shutdown(); System.out.println(count); } private static void add(){ count++; } } package com.ghc.concurrence.ConcurrentPractice; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; import java.util.HashMap; public class MapExample { private static Map<Integer, Integer> map = new HashMap<Integer,Integer>(); private static int threadNum = 200; private static int clientNum = 5000; public static void main(String[] args){ ExecutorService exec = Executors.newCachedThreadPool(); final Semaphore semaphore = new Semaphore(threadNum); for(int index = 0;index < clientNum; index++){ final int threadNum = index; exec.execute(()->{ try { semaphore.acquire(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } func(threadNum); semaphore.release(); }); } exec.shutdown(); System.out.println(map.size()); } public static void func(int threadNum){ map.put(threadNum, threadNum); } }
String info = "中文"; byte[] infoBytes = info.getBytes(StandardCharsets.UTF_8); String decodeInfo = new String(infoBytes,StandardCharsets.UTF_8); System.out.println("are they equals ?: "+Objects.equals(info,decodeInfo));
byte a = 127; byte b = 127; a = a+b; // 編譯不經過, + 操做有會提高爲 int 須要 強轉 a = (byte) (a+b); a+=b; System.out.println(a) ; // -2
<?xml version="1.0" encoding="UTF-8"?> <!--日誌級別以及優先級排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL --> <!--Configuration後面的status,這個用於設置log4j2自身內部的信息輸出,能夠不設置,當設置成trace時,你會看到log4j2內部各類詳細輸出--> <!--monitorInterval:Log4j可以自動檢測修改配置 文件和從新配置自己,設置間隔秒數--> <configuration status="WARN" monitorInterval="30"> <!--先定義全部的appender--> <appenders> <!--這個輸出控制檯的配置--> <console name="Console" target="SYSTEM_OUT"> <!--輸出日誌的格式--> <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/> </console> <!--文件會打印出全部信息,這個log每次運行程序會自動清空,由append屬性決定,這個也挺有用的,適合臨時測試用--> <File name="log" fileName="log/test.log" append="false"> <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/> </File> <!-- 這個會打印出全部的info及如下級別的信息,每次大小超過size,則這size大小的日誌會自動存入按年份-月份創建的文件夾下面並進行壓縮,做爲存檔--> <RollingFile name="RollingFileInfo" fileName="${sys:user.home}/logs/info.log" filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log"> <!--控制檯只輸出level及以上級別的信息(onMatch),其餘的直接拒絕(onMismatch)--> <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/> <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/> <Policies> <TimeBasedTriggeringPolicy/> <SizeBasedTriggeringPolicy size="100 MB"/> </Policies> </RollingFile> <RollingFile name="RollingFileWarn" fileName="${sys:user.home}/logs/warn.log" filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log"> <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/> <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/> <Policies> <TimeBasedTriggeringPolicy/> <SizeBasedTriggeringPolicy size="100 MB"/> </Policies> <!-- DefaultRolloverStrategy屬性如不設置,則默認爲最多同一文件夾下7個文件,這裏設置了20 --> <DefaultRolloverStrategy max="20"/> </RollingFile> <RollingFile name="RollingFileError" fileName="${sys:user.home}/logs/error.log" filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log"> <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/> <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/> <Policies> <TimeBasedTriggeringPolicy/> <SizeBasedTriggeringPolicy size="100 MB"/> </Policies> </RollingFile> </appenders> <!--而後定義logger,只有定義了logger並引入的appender,appender纔會生效--> <loggers> <!--過濾掉spring和mybatis的一些無用的DEBUG信息--> <logger name="org.springframework" level="INFO"></logger> <logger name="org.mybatis" level="INFO"></logger> <root level="all"> <appender-ref ref="Console"/> <appender-ref ref="RollingFileInfo"/> <appender-ref ref="RollingFileWarn"/> <appender-ref ref="RollingFileError"/> </root> </loggers> </configuration>
23)Java 中 ++ 操做符是線程安全的嗎? 不是線程安全的操做。它涉及到多個指令,如讀取變量值,增長,而後存儲回內存,這個過程可能會出現多個線程交差。 clone 是 Object 類的 本地方法 Number number = new Float(123); Integer integer = (Integer) number; // Exception in thread "main" java.lang.ClassCastException: java.lang.Float cannot be cast to java.lang.Integer 咱們能在 Switch 中使用 String 嗎? 從 Java 7 開始,咱們能夠在 switch case 中使用字符串,但這僅僅是一個語法糖。內部實如今 switch 中使用字符串的 hash code。 32)Serial 與 Parallel GC之間的不一樣之處? Serial 與 Parallel 在GC執行的時候都會引發 stop-the-world。它們之間主要不一樣 serial 收集器是默認的複製收集器,執行 GC 的時候只有一個線程,而 parallel 收集器使用多個 GC 線程來執行。 38)32 位 JVM 和 64 位 JVM 的最大堆內存分別是多數? 理論上說上 32 位的 JVM 堆內存能夠到達 2^32,即 4GB,但實際上會比這個小不少。不一樣操做系統之間不一樣,如 Windows 系統大約 1.5 GB,Solaris 大約 3GB。64 位 JVM容許指定最大的堆內存,理論上能夠達到 2^64,這是一個很是大的數字,實際上你能夠指定堆內存大小到 100GB。甚至有的 JVM,如 Azul,堆內存到 1000G 都是可能的。 Runtime runtime = Runtime.getRuntime(); Long freeMemory = runtime.freeMemory(); Long totalMemory = runtime.totalMemory(); Long maxMemory = runtime.maxMemory(); System.out.println("freeMemory: "+freeMemory/(1024*1024)+"MB"); System.out.println("totalMemory: "+totalMemory/(1024*1024)+"MB"); System.out.println("maxMemory: "+maxMemory/(1024*1024)+"MB"); /* freeMemory: 240MB totalMemory: 245MB maxMemory: 3625MB*/ 41)你能保證 GC 執行嗎? 不能,雖然你能夠調用 System.gc() 或者 Runtime.getRuntime().gc(),可是沒有辦法保證 GC 的執行。 42)怎麼獲取 Java 程序使用的內存?堆使用的百分比? 能夠經過 java.lang.Runtime 類中與內存相關方法來獲取剩餘的內存,總內存及最大堆內存。經過這些方法你也能夠獲取到堆使用的百分比及堆內存的剩餘空間。Runtime.freeMemory() 方法返回剩餘空間的字節數,Runtime.totalMemory() 方法總內存的字節數,Runtime.maxMemory() 返回最大內存的字節數。 43)Java 中堆和棧有什麼區別? JVM 中堆和棧屬於不一樣的內存區域,使用目的也不一樣。棧經常使用於保存方法幀和局部變量,而對象老是在堆上分配。棧一般都比堆小,也不會在多個線程之間共享,而堆被整個 JVM 的全部線程共享。 Difference between stack and heap memory in Java finally 中 不建議 拋出異常,由於 finally 中若是有異常出現,那麼 finally 老是優先於 try 代碼塊中的 代碼執行 ,這時候 try 中的 異常 若是沒有作 特殊處理是不會被 捕獲到的,由於 finally 先拋了一個異常,那麼 咱們就極可能丟失異常, 這時候 能夠在 finally 外部定義一個 Super。。。。 addSusp。。。, 但仍然不建議這麼作。 47)Java 中的編譯期常量是什麼?使用它又什麼風險? 公共靜態不可變(public static final )變量也就是咱們所說的編譯期常量,這裏的 public 可選的。實際上這些變量在編譯時會被替換掉,由於編譯器知道這些變量的值,而且知道這些變量在運行時不能改變。這種方式存在的一個問題是你使用了一個內部的或第三方庫中的公有編譯時常量,可是這個值後面被其餘人改變了,可是你的客戶端仍然在使用老的值,甚至你已經部署了一個新的jar。爲了不這種狀況,當你在更新依賴 JAR 文件時,確保從新編譯你的程序。 // 打印 數組 Arrays.toString(arr) or Arrays.deepToString(arr) Person p1 = new Person("a","f",18); Person p2 = new Person("b","m",19); Person p3 = new Person("c","f",20); Person [] p = new Person[]{p1,p2,p3}; System.out.println(Arrays.toString(p)); Java 中的 TreeMap 是使用紅黑樹實現的。 HashTable 線程安全不能夠用 null 作key , 而 HashMap 沒有同步策略能夠用 null 作 key ,一樣須要 覆寫 equals hashCode 方法 HashMap<String, Person> personHashMap = new HashMap<>(); personHashMap.put(null,new Person("a","f",18)); personHashMap.put(null,new Person("b","m",20)); System.out.println(personHashMap); // {null=b|20|m} List<Person> personList = new ArrayList<Person>(); personList.add(new Person("a","f",18)); personList.add(new Person("b","m",18)); personList.add(new Person("c","f",18)); Iterator<Person> it = personList.iterator(); while(it.hasNext()){ Person p = it.next(); if("c".equals(p.getName())){ System.out.println("start to remove "+p.getName()); personList.remove(p); // 這是錯誤的 會出現 Exception in thread "main" java.util.ConcurrentModificationException it.remove(); // 這是對的 } } System.out.println(personList); 59)咱們能本身寫一個容器類,而後使用 for-each 循環嗎? 能夠,你能夠寫一個本身的容器類。若是你想使用 Java 中加強的循環來遍歷,你只須要實現 Iterable 接口。若是你實現 Collection 接口,默認就具備該屬性 這一點 就跟 python 中 實現 迭代器協議 __iter__ 一個道理 61)有沒有可能兩個不相等的對象有有相同的 hashcode? 有可能,兩個不相等的對象可能會有相同的 hashcode 值,這就是爲何在 hashmap 中會有衝突。相等 hashcode 值的規定只是說若是兩個對象相等,必須有相同的hashcode 值,可是沒有關於不相等對象的任何規定。 因此咱們在 覆寫 equals 方法的 同時要 覆寫 hashCode 方法,減小 hash 碰撞 65)爲何在重寫 equals 方法的時候須要重寫 hashCode 方法?(答案) 由於有強制的規範指定須要同時重寫 hashcode 與 equal 是方法,許多容器類,如 HashMap、HashSet 都依賴於 hashcode 與 equals 的規定 public static void main(String [] args) { test(); } public static void add(Byte b) { b = b++; } public static void test() { Byte a = 127; Byte b = 127; add(++a); System.out.print(a + " "); add(b); System.out.print(b + ""); } // -128 127
public static void main(String [] args) { /*假設有一個數組 A ,int[] A = { 1 , 3 , -1 ,0 , 2 , 1 , -4 , 2 , 0 ,1 ... N}; 原來是須要查出大於0的數組,可是因爲傳參錯誤或者其餘緣由,致使查出0和負數了, 如今要求在不使用新數組和新集合的狀況下(即只使用這個A數組,因數組數據比較大, 且只能用一次循環) 實現正數放到數組的前面,小於等於0的數放到數組的末尾*/ int[] arr = { 5,6,7,8,9,10,11,-1,-2,-3,-4}; int base = 0; int midIndex = arr.length/2; int midValue = arr[midIndex]; arr[midIndex] = base; // 先將 最中間位置 換位 0 int start = 0, end = arr.length-1; while(start<end){ System.out.println("start: "+start+" | end: "+end); System.out.println(Arrays.toString(arr)); if(arr[start] < base) {start++; if(arr[end] < base){ swap(arr,midIndex,end); } end--; } else if(arr[start]>base){ swap(arr,start,midIndex); if(arr[end] < base){ swap(arr,start,end); } start++; end--; }else{ break; } } System.out.println("********"); System.out.println(Arrays.toString(arr)); if(arr[0] == base){ swap(arr,0,end+1); } if(arr[arr.length-1] == base){ swap(arr,start-1,arr.length-1); } // 將中間那個值還原回去 arr[start-1] = midValue; System.out.println(Arrays.toString(arr)); }
package com.ghc.test; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) throws Exception { List<Thread> threads = new ArrayList<>(); for (String name : Arrays.asList("Bob", "Alice", "Tom")) { threads.add(new HelloThread(name)); } System.out.println("START"); for (Thread t : threads) { t.start(); //t.join(); //在這裏 join 的話,會等待一個 線程完成纔會開啓下一個 線程 } for(Thread t: threads){ t.join(); } System.out.println("END"); } } class HelloThread extends Thread { String name; public HelloThread(String name) { this.name = name; } @Override public void run() { System.out.println("Hello, " + name + "!"); try { Thread.sleep(1000); } catch (InterruptedException e) { } System.out.println("Goodbye, " + name + "!"); } }
main--> start... Thread-0--> running... Thread-1--> running... main--> end... ThreadSafe.COUNTER: 10 package com.ghc.test; import java.util.ArrayList; import java.util.List; /** * @author :Frank Li * @date :Created in 2019/7/9 14:32 * @description:${description} * @modified By: * @version: $version$ */ public class ThreadSafe { public static int COUNTER = 0; public static final int LOOP = 10000; public static void main(String [] args) throws Exception{ System.out.println(Thread.currentThread().getName()+"--> start..."); Thread t1 = new Thread(new AddThread()); Thread t2 = new SubstractThread(); List<Thread> threadList = new ArrayList<>(); threadList.add(t1); threadList.add(t2); for(Thread t:threadList){ t.start(); } for(Thread t:threadList){ t.join(); } System.out.println(Thread.currentThread().getName()+"--> end..."); System.out.println("ThreadSafe.COUNTER: "+ThreadSafe.COUNTER); } } class AddThread implements Runnable{ @Override public void run(){ System.out.println(Thread.currentThread().getName()+"--> running..."); for(int i=0;i<ThreadSafe.LOOP;i++){ ThreadSafe.COUNTER += 1; // 非原子性操做 } } } class SubstractThread extends Thread{ @Override public void run(){ System.out.println(Thread.currentThread().getName()+"--> running..."); for(int i=0;i<ThreadSafe.LOOP;i++){ ThreadSafe.COUNTER -= 1; // 非原子性操做 } } }
package com.ghc.test; import java.util.ArrayList; import java.util.List; /** * @author :Frank Li * @date :Created in 2019/7/9 14:32 * @description:${description} * @modified By: * @version: $version$ */ public class ThreadSafe { public static int COUNTER = 0; public static final int LOOP = 10000; public static void main(String [] args) throws Exception{ System.out.println(Thread.currentThread().getName()+"--> start..."); Thread t1 = new Thread(new AddThread()); Thread t2 = new SubstractThread(); List<Thread> threadList = new ArrayList<>(); threadList.add(t1); threadList.add(t2); for(Thread t:threadList){ t.start(); } for(Thread t:threadList){ t.join(); } System.out.println(Thread.currentThread().getName()+"--> end..."); System.out.println("ThreadSafe.COUNTER: "+ThreadSafe.COUNTER); } } class AddThread implements Runnable{ @Override public void run(){ System.out.println(Thread.currentThread().getName()+"--> running..."); for(int i=0;i<ThreadSafe.LOOP;i++){ synchronized (Main.class) { ThreadSafe.COUNTER += 1; // 非原子性操做 包括 ILOAD IADD ISTORE 三個操做 } } } } class SubstractThread extends Thread{ @Override public void run(){ System.out.println(Thread.currentThread().getName()+"--> running..."); for(int i=0;i<ThreadSafe.LOOP;i++){ synchronized (Main.class) { ThreadSafe.COUNTER -= 1; // 非原子性操做 包括 ILOAD IADD ISTORE 三個操做 } } } }
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Counter { private final Lock lock = new ReentrantLock(); private int value; public void inc(int m){ if(lock.tryLock()){ // 若是獲取到了鎖才進入 try{ this.value+=m; }finally{ lock.unlock(); } } } public void dec(int m){ if(lock.tryLock()){ try{ this.value-=m; }finally { lock.unlock(); } } } }
java面試知識點總結(持續更新,歡迎star,fork補充)面試
相同點:
都不能被實例化
都包含抽象方法,這些抽象方法用於描述系統能提供哪些服務,而這些服務是由子類來提供實現的
在系統設計上,二者都表明系統的抽象層,當一個系統使用一棵繼承樹上的類時,應該儘可能把引用變量聲明爲繼承樹的上層抽象類型,這樣能夠提升兩個系統之間的鬆耦合
不一樣點:
在抽象類中能夠爲部分方法提供默認的實現,從而避免在子類中重複實現它們;可是抽象類不支持多繼承。接口不能提供任何方法的實現,可是支持多繼承。
接口表明了接口定義者和接口實現者的一種契約;而抽象類和具體類通常而言是一種繼承的關係,即二者在概念本質上是不一樣。算法
1.內部類能夠很好的實現隱藏,通常的非內部類,是不容許有 private 與protected權限的,但內部類能夠
2.內部類擁有外圍類的全部元素的訪問權限
3.可實現多重繼承spring
靜態內部類,定義在類中,任何方法外,用static定義;靜態內部類只能訪問外部類的靜態成員。
生成(new)一個靜態內部類不須要外部類成員:這是靜態內部類和成員內部類的區別。靜態內部類的對象能夠直接生成:Outer.Inner in=new Outer.Inner();而不須要經過生成外部類對象來生成。這樣實際上使靜態內部類成爲了一個頂級類。能夠定義私有靜態內部類。數據庫
是否能夠建立靜態的成員方法與成員變量(靜態內部類能夠建立靜態的成員而非靜態的內部類不能夠)、對於訪問外部類的成員的限制(靜態內部類只能夠訪問外部類中的靜態成員變量與成員方法而非靜態的內部類便可以訪問靜態的也能夠訪問非靜態的外部類成員方法與成員變量)。這兩個差別是靜態內部類與非靜態外部類最大的差別,也是靜態內部類之因此存在的緣由apache
重寫"只能適用於實例方法.不能用於靜態方法.對於靜態方法,只能隱藏(形式上被重寫了,可是不符合的多態的特性),「重寫」是用來實現多態性的,只有實例方法是能夠實現多態,而靜態方法沒法實現多態
自動裝箱是 Java 編譯器在基本數據類型和對應的對象包裝類型之間作的一個轉化。
好比:把 int 轉化成 Integer,double 轉化成 Double等,反之就是自動拆箱。
Integer a=1;//這就是一個自動裝箱,若是沒有自動裝箱的話,須要這樣Integer a=new Integer(1)
int b=a;//這就是一個自動拆箱,若是沒有自動拆箱的話,須要這樣:int b=a.intValue()
這樣就能看出自動裝箱和自動拆箱是簡化了基本數據類型和相對應對象的轉化步驟
Java中的自動裝箱與拆箱
一是爲了在各類類型間轉化,經過各類方法的調用。不然你沒法直接經過變量轉化。
好比,如今int要轉爲String
int a=0;
String result=Integer.toString(a);
二是好比我如今要用泛型
List
這裏<>須要類。若是你用int。它會報錯的
(1) 用 new 語句建立對象,這是最多見的建立對象的方法
(2) 運用反射手段,調用 java.lang.Class 或者 java.lang.reflect.Constructor 類的 newInstance() 實例方法
(3) 調用對象的 clone() 方法
(4) 運用反序列化手段,調用 java.io.ObjectInputStream 對象的 readObject() 方法
(1)和(2)都會明確的顯式的調用構造函數;(3)是在內存上對已有對象的影印,因此不會調用構造函數 (4)是從文件中還原類的對象,也不會調用構造函數。
對象序列化(Serializable)是指將對象轉換爲字節序列的過程,而反序列化則是根據字節序列恢復對象的過程。
序列化通常用於如下場景:
1.永久性保存對象,保存對象的字節序列到本地文件中;
2.經過序列化對象在網絡中傳遞對象;
3.經過序列化在進程間傳遞對象。
只有實現了Serializable和Externalizable接口的類的對象才能被序列化,
java.io.ObjectOutputStream表明對象輸出流,它的writeObject(Objectobj)方法可對參數指定的obj對象進行序列化,把獲得的字節序列寫到一個目標輸出流中。
java.io.ObjectInputStream表明對象輸入流,它的readObject()方法從一個源輸入流中讀取字節序列,再把它們反序列化爲一個對象,並將其返回。
Java 中的方法重載發生在同一個類裏面兩個或者是多個方法的方法名相同可是參數不一樣的狀況;
方法覆蓋是說子類從新定義了父類的方法,方法覆蓋必須有相同的方法名,參數列表和返回類型。
一般咱們定義一個基本數據類型的變量,一個對象的引用,還有就是函數調用的現場保存都使用內存中的棧空間;而經過new關鍵字和構造器建立的對象放在堆空間;程序中的字面量(literal)如直接書寫的100、「hello」和常量都是放在靜態存儲區中。棧空間操做最快可是也很小,一般大量的對象都是放在堆空間,整個內存包括硬盤上的虛擬內存均可以被當成堆空間來使用。
String str = new String(「hello」);
上面的語句中 str 放在棧上,用 new 建立出來的字符串對象放在堆上,而「hello」這個字面量放在靜態存儲區。
強引用:如「Object obj = new Object()」,這類引用是 Java 程序中最廣泛的。只要強引用還存在,垃圾收集器就永遠不會回收掉被引用的對象。
軟引用:它用來描述一些可能還有用,但並不是必須的對象。在系統內存不夠用時,這類引用關聯的對象將被垃圾收集器回收。JDK1.2 以後提供了 SoftReference 類來實現軟引用。
弱引用:它也是用來描述非需對象的,但它的強度比軟引用更弱些,被弱引用關聯的對象只能生存島下一次垃圾收集發生以前。當垃圾收集器工做時,不管當前內存是否足夠,都會回收掉只被弱引用關聯的對象。在 JDK1.2 以後,提供了 WeakReference 類來實現弱引用。
虛引用:最弱的一種引用關係,徹底不會對其生存時間構成影響,也沒法經過虛引用來取得一個對象實例。爲一個對象設置虛引用關聯的惟一目的是但願能在這個對象被收集器回收時收到一個系統通知。JDK1.2 以後提供了 PhantomReference 類來實現虛引用。
Java 7之基礎 - 強引用、弱引用、軟引用、虛引用
Java垃圾回收機制與引用類型
內存管理與垃圾回收
在C++中,對象所佔的內存在程序結束運行以前一直被佔用,在明確釋放以前不能分配給其它對象;而在Java中,當沒有對象引用指向原先分配給某個對象的內存時,該內存便成爲垃圾。JVM的一個系統級線程會自動釋放該內存塊。垃圾收集意味着程序再也不須要的對象是"無用信息",這些信息將被丟棄。當一個對象再也不被引用的時候,內存回收它佔領的空間,以便空間被後來的新對象使用。事實上,除了釋放沒用的對象,垃圾收集也能夠清除內存記錄碎片。因爲建立對象和垃圾收集器釋放丟棄對象所佔的內存空間,內存會出現碎片。碎片是分配給對象的內存塊之間的空閒內存洞。碎片整理將所佔用的堆內存移到堆的一端,JVM將整理出的內存分配給新的對象。
垃圾收集能自動釋放內存空間,減輕編程的負擔。這使Java虛擬機具備一些優勢。首先,它能使編程效率提升。在沒有垃圾收集機制的時候,可能要花許多時間來解決一個難懂的存儲器問題。在用Java語言編程的時候,靠垃圾收集機制可大大縮短期。其次是它保護程序的完整性, 垃圾收集是Java語言安全性策略的一個重要部份。垃圾收集的一個潛在的缺點是它的開銷影響程序性能。Java虛擬機必須追蹤運行程序中有用的對象,並且最終釋放沒用的對象。這一個過程須要花費處理器的時間。其次垃圾收集算法的不完備性,早先採用的某些垃圾收集算法就不能保證100%收集到全部的廢棄內存。固然隨着垃圾收集算法的不斷改進以及軟硬件運行效率的不斷提高,這些問題均可以迎刃而解。
通常來講,Java開發人員能夠不重視JVM中堆內存的分配和垃圾處理收集,可是,充分理解Java的這一特性可讓咱們更有效地利用資源。同時要注意finalize()方法是Java的缺省機制,有時爲確保對象資源的明確釋放,能夠編寫本身的finalize方法。(引用自百度)
Java 垃圾收集機制
由Collection接口派生的兩個接口是List和Set;
Vector很是相似ArrayList,可是Vector是同步的;
Stack繼承自Vector,實現一個後進先出的堆棧,push和pop,還有peek方法獲得棧頂的元素
Set是一種不包含重複的元素的Collection
Map沒有繼承Collection接口,Map提供key到value的映射,一個Map中不能包含相同的key,每一個key只能映射一個 value
集合你們族
1,vector是線程同步的,因此它也是線程安全的,而arraylist是線程異步的,是不安全的。若是不考慮到線程的安全因素,通常用arraylist效率比較高。
2,若是集合中的元素的數目大於目前集合數組的長度時,vector增加率爲目前數組長度的100%,而arraylist增加率爲目前數組長度的50%.如過在集合中使用數據量比較大的數據,用vector有必定的優點。
3,若是查找一個指定位置的數據,vector和arraylist使用的時間是相同的,都是0(1),這個時候使用vector和arraylist均可以
添加數據使用put(key, value),取出數據使用get(key),這兩個基本操做的時間開銷爲常數。
Hashtable經過initial capacity和load factor兩個參數調整性能。一般缺省的load factor 0.75較好地實現了時間和空間的均衡。增大load factor能夠節省空間但相應的查找時間將增大,這會影響像get和put這樣的操做。
HashMap Hashtable區別HashMap是Hashtable的輕量級實現(非線程安全的實現),效率上可能高於Hashtable。他們都完成了Map接口。HashMap容許null值做爲key和value,而Hashtable不能夠。
最大的不一樣是,Hashtable的方法是Synchronize的,而HashMap不是,在多個線程訪問Hashtable時,不須要本身爲它的方法實現同步,而HashMap 就必須爲之提供外同步(Collections.synchronizedMap)。
迭代HashMap採用快速失敗機制(不是迭代完成後才告訴你出錯了),而Hashtable不是。迭代器的快速失敗機制會拋出一個併發修改異常 (ConcurrentModificationException) ,應該僅用於檢測程序錯誤。
咱們知道java.util.HashMap不是線程安全的,所以若是在使用迭代器的過程當中有其餘線程修改了map,那麼將拋出ConcurrentModificationException,這就是所謂fail-fast策略。這一策略在源碼中的實現是經過modCount域,modCount顧名思義就是修改次數,對HashMap內容的修改都將增長這個值,那麼在迭代器初始化過程當中會將這個值賦給迭代器的expectedModCount。在迭代過程當中,判斷modCount跟expectedModCount是否相等,若是不相等就表示已經有其餘線程修改了Map。modCount聲明爲volatile,保證線程之間修改的可見性。
Java中的hashCode方法就是根據必定的規則將與對象相關的信息(好比對象的存儲地址,對象的字段等)映射成一個數值,這個數值稱做爲散列值。
若是集合中已經存在一萬條數據或者更多的數據,若是採用equals方法去逐一比較,效率必然是一個問題。此時hashCode方法的做用就體現出來了,當集合要添加新的對象時,先調用這個對象的hashCode方法,獲得對應的hashcode值,實際上在HashMap的具體實現中會用一個table保存已經存進去的對象的hashcode值,若是table中沒有該hashcode值,它就能夠直接存進去,不用再進行任何比較了;若是存在該hashcode值,就調用它的equals方法與新元素進行比較,相同的話就不存了,不相同就散列其它的地址,因此這裏存在一個衝突解決的問題,這樣一來實際調用equals方法的次數就大大下降了。
hashcode方法的做用
一、hashCode的存在主要是用於查找的快捷性,如Hashtable,HashMap等,hashCode是用來在散列存儲結構中肯定對象的存儲地址的;
二、若是兩個對象相同,就是適用於equals(java.lang.Object) 方法,那麼這兩個對象的hashCode必定要相同;
三、若是對象的equals方法被重寫,那麼對象的hashCode也儘可能重寫,而且產生hashCode使用的對象,必定要和equals方法中使用的一致,不然就會違反上面提到的第2點;
四、兩個對象的hashCode相同,並不必定表示兩個對象就相同,也就是不必定適用於equals(java.lang.Object)方法,只可以說明這兩個對象在散列存儲結構中,如Hashtable,他們「存放在同一個籃子裏」。
HashCode和equal方法
守護線程,是指用戶程序在運行的時候後臺提供的一種通用服務的線程。只要當前JVM實例中尚存在任何一個用戶線程沒有結束,守護線程就所有工做;只有當最後一個用戶線程結束時,守護線程隨着 JVM 一同結束工做。 守護線程最典型的應用就是 GC (垃圾回收器)。
JAVA併發編程——守護線程(Daemon Thread)
一個進程對應一個程序的執行,而一個線程則是進程執行過程當中的一個單獨的執行序列,一個進程能夠包含多個線程。線程有時候也被稱爲輕量級進程。
一個Java虛擬機的實例運行在一個單獨的進程中,不一樣的線程共享Java虛擬機進程所屬的堆內存。這也是爲何不一樣的線程能夠訪問同一個對象。線程彼此共享堆內存並保有他們本身獨自的棧空間。這也是爲何當一個線程調用一個方法時,他的局部變量能夠保證線程安全。但堆內存並非線程安全的,必須經過顯示的聲明同步來確保線程安全。
package com.algorithms; import java.util.Arrays; /** * @author :Frank Li * @date :Created in 2019/10/21 9:35 * @description:${description} * @modified By: * @version: $version$ */ public class Sorter { public static void main(String[] args) { int [] arr = {10,9,8,7,6,5,4,3,2,1}; System.out.println(Arrays.toString(arr)+"\\n"); quickSort(arr, 0, arr.length-1); System.out.println(Arrays.toString(arr)); } public static void quickSort(int [] arr, int leftBound, int rightBound){ if(leftBound>=rightBound){return;} int mid = partition(arr, leftBound, rightBound); quickSort(arr, leftBound, mid-1); quickSort(arr, mid+1, rightBound); } public static int partition(int[] arr, int leftBound, int rightBound){ int left = leftBound; int base = rightBound - 1; int right = rightBound; while(left < right){ while(arr[left] < arr[base]) {left++;} while(arr[right] > arr[base]) {right--;} if(left<right){swap(arr, left, right);} } // 換比較的 基準值 if(arr[left]<arr[base]) {swap(arr, left, base);} return left; } public static void swap(int[] arr, int left, int right){ int tmp = arr[left]; arr[left] = arr[right]; arr[right] = tmp; } }
2017屆春招秋招公司的面試題目
快速排序
二叉樹遍歷
UML類圖
1.Java中final,finally,finalize的區別
2.hashmap的特性是什麼,和hashtable的區別
3.java線程中sleep和wait方法區別
4.談談經常使用容器類的原理和應用場景
1.一個文件中有100萬個整數,由空格分開,在程序中判斷用戶輸入的整數是否在此文件中。說出最優的方法
1.arraylist與vector的區別
2.優化view
3.線程安全
4.實現樹
5.內存限制
6.枚舉
7.安卓性能優化工具
1.寫出知道的全部單例模式的寫法
2.整數的二進制找出有幾個1,效率要求最高
3.會場安排問題
4.如何用兩個棧模擬一個隊列
(前面四道考了快40分鐘了)
5.TCP三次握手的過程
6.http瞭解嗎?(這道我直接說沒有深刻研究web開發)
7.java集合類,哪些線程安全,哪些線程不安全
8.線程安全問題(如何保證線程安全,哪些地方要使用線程安全;lock和synchronized區別,用哪一個更好,爲何?)
9.用過volatile嗎,說一下?
10.有看過JDK源碼嗎?(這個我說沒有深刻了解過)
11.數據庫隔離級別哪幾種?(這道直接說忘了,能夠提示一下嗎)
12.其餘問題忘了
(沒問項目,全問基礎題,算法題最重要,答很差估計進不了)
1.詳細問了項目的整個架構和一些具體功能,關鍵技術的實現?(談了估計快半個鍾)
2.TCP三次握手,以及一些具體問題如」爲何要有第三次握手?客戶端發給服務器的報文段丟失了怎麼辦?這時客戶端還沒收到服務器的確認包,那它會繼續發嗎?服務器收到以後重傳的確認號應該是多少?」等等(兩輪都問了TCP,總的來講就是要精通TCP,滑動窗口,確認重傳都要很清楚)
3.線程安全問題(同一面)
4.平衡二叉樹(說一下原理?開發實踐中哪些地方要用到它?)
5.一個字符串中找出給定字符串,要求效率最高?(字符串匹配的KMP算法)
6.若是HashMap的大小超過了負載因子定義的容量,怎麼辦?
7.說一下hashcode?(本身關聯了equals和==回答)
8.知道Unicode編碼嗎?(這道我直接說沒有深刻研究,怕被問深)
9.其餘細節題,如char a=‘海’;float a=1.1; short a=1;分別問了這幾個正確嗎?
10.想問一道機率論的題目(我直接跟面試官說沒修這門課,廣外以前把機率論當選修課了…面試官也說那算了)
11.學習理論和作項目你是怎麼看的?
12.問了個人職業規劃是什麼?
13.考不考研,爲何?
(能過估計是TCP,線程安全和hashcode與equals這幾道題我答的比較好,面試官一直在點頭)
1.看到個人實踐經歷,問我怎麼在學習中能抽出時間作這些實踐?
2.看到我以前被內推過安卓,問爲何從安卓轉作java?(我給了不少緣由,面試官都表示不理解。。)
3.說一下職業規劃?怎麼學習本身這個方向?
4.詳細介紹一個本身的項目?
5.本身擴展過的網絡通訊框架有測試過性能嗎,比原框架好在哪裏?從幾個指標來回答?
6.實習去哪一個城市都行嗎?
(hr面表現不太好,沒有事先準備)
1.一次完整的http訪問流程
2.圖片內存緩存LRUCache怎麼實現
3.App點擊桌面圖標的啓動流程
4.如何進程間通訊?
5.看過Binder源碼嗎,底層怎麼實現
6.Android新版本的特性,如何實現的
(兩個面試官輪流問...)
1.項目介紹,畫架構圖
2.手寫代碼實現一個棧
3.TCP握手過程
4.說一下內存溢出
5.遇過內存泄漏嗎
6.設計模式,說一下抽象工廠
7.線程模型是怎樣的(難倒我了,沒複習操做系統...)
8.如何進程間通訊?
9.AIDL如何實現?
10.說一下事件分發機制(這裏仍是沒理解透)
1.項目介紹,畫架構圖
2.實習的工做內容
3.手寫快速排序
4.一道挺有意思的軟件架構設計題,要求設計具備擴展性
5.後面幾乎都在自我展示技術了(說了binder機制的內部實現)
1.家庭狀況,性格,缺點各類...
2.什麼狀況下你會拒絕cvte的offer?
1.先作算法題
二叉搜索樹與雙向鏈表
輸入一棵二叉搜索樹,將該二叉搜索樹轉換成一個排序的雙向鏈表。要求不能建立任何新的結點,只能調整樹中結點指針的指向。
2.TCP三次握手和四次揮手的過程,timewait,closewait狀態分別在哪
3.osi分層
4.進程間通訊方式
5.分頁與分段的區別,各自有什麼優缺點
6.HashMap、HashTable區別,concurrentHashmap
7.B樹
8.java中軟引用,虛引用,弱引用區別
9.classLoader
10.gc垃圾回收,分代回收
11.深拷貝 淺拷貝
12.靜態內部類,內部類,匿名內部類
13.反射機制
14.sleep()和wait()區別,在同步方法中哪一個能夠釋放鎖?
算法題:
給定文件格式以下
1.1.1.2 1.1.1.200 100
3.2.2.1 3.2.2.144 102
..
每一行表明: 起始IP 結束IP 省份編號
求指定IP的所在省份
int searchProv(char *ip)
可寫僞代碼 時間10分鐘。
(題意都看錯,因此被刷了T T)
(項目上問了編譯器,給一條語句讓我畫出語法樹)
1.說一下final的意義
2.java集合類都問了一遍(基礎)
3.如何設計StringBuffer(沒答好)
4.死鎖的定義,哪4個條件?
5.單例模式
6.手寫二分查找,冒泡排序(面試官注重代碼細節)
7.activity生命週期,啓動模式(問的比較細,singleInstance的activity開啓一個新activity,任務棧是怎樣狀態)
8.handler底層實現?消息隊列爲空會怎樣?(會發生空閒等待,其實就是利用了管道機制)
(面試官也是先問編譯器,大公司對這個感興趣)
1.hashmap的內部實現
2.說一下堆棧的內存結構
3.設計一個棧(不用list,set或map)
4.Asynctask內部實現
5.設計一個線程池?(以前阿里還考過,然而仍是不會...)
6.sleep()和wait()使用過程要注意什麼?
7.如何設計一個阻塞隊列 ?
8.斐波那契數列的實現(手寫遞歸和非遞歸)
9.字符串第一個出現一次的字符(遍歷一遍,時間o(n),用數組int[256]或hashmap存儲)
10.什麼是滿二叉樹,下個定義?(我說了當深度爲n時,葉子節點數爲2^(n-1)的樹...)
11.堆排序,如何初建大根堆?
12.又問了Activity啓動模式
13.如何實現AIDL?
1.有一個數列有10萬個數,另外一個數列是1億個數,找出這兩個數列共同擁有的數
2.TCP
3.畫HTTP報文
4.短鏈接和長鏈接
5.兩臺服務器不一樣地方,傳輸一個文件須要考慮什麼因素
6.數據庫索引
7.B樹,B+樹
8.平時怎麼學習,學習方法?
9.意向工做地點,工做業務?
一面是電話面試,而後通知到公司面試,先寫作一份筆試,後面三輪面試
java基礎,排序算法之類
比較難的一道算法題,設計數據結構,手寫代碼 機票路線,從A地到B地不能直達,要中轉1個站,求須要中轉1個站的路線佔全部路線比例