1、java语法基础java
一、finalc++
关于final的问题我曾经被问到两次,因此首先说一下这个东西。编程
应用于变量,表示该变量一旦被赋值则不能够改变,可是有一个特殊的:StringBuffer,看下面一个例子设计模式
final StringBuffer sb=new StringBuffer("123");数组
这样写 sb=new StringBuffer("");会报错,可是sb.append("111");不会报错。安全
final是指引用变量不能变,但变量的内容是不能够改变的。StringBuffer 只是有这样一个方法能够改变它的内容而已。数据结构
应用于方法,表示该方法不能够被重写覆盖。多线程
应用与类,表示该类不能够被继承。app
二、关于private,public,protected,friendly异步
能够用一个表格说明他们的权限和访问范围,当修饰元素没有修饰符时默认是friendly
- 表示不支持 √ 表示支持
修饰符 | 当前类 | 同一包 | 子孙类 | 其余包 |
public | √ | √ | √ | √ |
protected | √ | √ | √ | - |
friendly | √ | √ | - | - |
private | √ | - | - | - |
三、基本数据类型
byte、int、short、double、float、long、double、boolean
级别从低到高为:byte,char,short(这三个平级)-->int-->float-->long-->double
由低级到高级系统会自动转换,由高级到低级须要强制转换。
四、运算符
a++ 和++a区别
二者都表示a+1可是前者表示先进行运算,而后给a+1,后者表示先a+1,再参加运算,例如:a=2;b=a++;能够理解为b=a,a=a+1;b=++a;能够理解为a=a+1,b=a;一样a--和--a相似。
& 和 &&(| 和||)区别
首先二者都表示与运算符,两边条件均为true时结果才为true,其余状况均为false;
&&有短路功能,例如a&&b,当a为false时,就不会执行b;可是a&b无论a为true或者false,b都会执行。
& 还能够看成位运算符,两边表达式不是boolean类型时,表示按位与操做。
有一个关于位运算的题:请编程实现计算1234变成二进制之后包含多少1。
通常思路就是先经过Integer.toBinaryString(int i)方法转换成二进制,而后遍历里面1的个数。
这里说一下不一样进制之间的转换方法:
十进制转成十六进制:
Integer.toHexString(int i)
十进制转成八进制
Integer.toOctalString(int i)
十进制转成二进制
Integer.toBinaryString(int i)
十六进制转成十进制
Integer.valueOf("FFFF",16).toString()
八进制转成十进制
Integer.valueOf("876",8).toString()
二进制转十进制
Integer.valueOf("0101",2).toString()
其实经过位运算能够实现更快的方法。
public static void main(String[] args) { int c=0; int t=1234; while (t>0) { t=t&(t-1); c++; } System.out.print(c); }
说明一下,t&(t-1)实际上是 t 的二进制进行移位运算,0&1=0,1&0=0,1&1=1。
说道移位运算还有一个:请用最有效率的方法计算出2乘以8的结果。
2<<3 一个数左移几位就至关于这个数乘以2的几回方,2*八、等价于2左移3位
五、Override和Overload的区别(重写和重载区别)。
重载是指同一个类中能够存在多个命名相同的方法,可是各个方法的参数个数或类型必须不一样,而且不能够经过改变方法的返回值来表示两个方法的不通。
重写是指子类能够与父类的方法名称参数相同,等于彻底把父类的方法覆盖了。可是对于异常,子类的方法必须比父类抛出更少的异常或者是父类异常的子异常。
六、java内存
java内存大概分为5块:寄存器,本地方法区,方法区,堆,栈。
栈:主要用来存储局部变量,当运算完成所在趋于结束,内存将被释放。
堆:存储数组和对象。
七、成员变量和局部变量区别
成员变量在类里面定义,只在类里面有效;局部变量存在方法中定义,只在方法所在的大括号有效。
成员变量存在于堆内存中;局部变量存在与栈内存中。
八、this 和 super
this 一般用来表示对象自己,super访问父类被子类隐藏的变量或覆盖的方法。
若是一个类继承自父类,那么子类的super()方法即对父类的初始化。当类中有两个同名变量,一个属于类(类的成员变量),而另外一个属于某个特定的方法(方法中的局部变量),使用this区分红员变量和局部变量。
调用super()必须写在子类构造方法的第一行,不然编译不经过。每一个子类构造方法的第一条语句,都是隐含地调用super(),若是父类没有这种形式的构造函数,那么在编译的时候就会报错。
super()和this()相似,区别是,super从子类中调用父类的构造方法,this()在同一类内调用其它方法。
super的本质是java的一个关键字,this的本质是一个指向本对象的指针。
九、单例模式
保证一个类在内存中的对象中惟一性。
步骤:一、私有化构造函数。二、建立一个静态的私有的本类对象。三、提供一个对外调用的方法。
单例模式的建立有两种:懒汉式,饿汉式
首先来看下懒汉式:
public class Single { public static Single single; private Single(){ } public static Single getInstance(){ if (single==null) { single=new Single(); } return single; } }
能够看出当须要Single的时候,随时用随时new,这样之后就不用实例了,再看下饿汉式:
public class Single { public static Single singleInstance=new Single(); private Single(){ } public static Single getInstance(){ return single; } }
比较推荐饿汉式,由于他不用考虑线程安全问题,懒汉模式下若是有两个线程同时访问,第一个线程走到if后尚未执行new,第二个线程也会判断为Null,从新建立一个实例,这样就建立了两个。固然有一种方法能够解决这个问题那就是synchronized,看一下代码:
public class Single { public static Single single; private Single(){ } public synchronized static Single getInstance(){ if (single==null) { single=new Single(); } return single; } }
固然这样是能够的,实现了同步锁,可是其实还能够进行优化,这样每次调用getInstance()都会受同步锁的影响,效率会下降。其实只要保证new的时候同步就能够了,这种方法叫双重锁定(Double-Check Locking)有兴趣的能够查一下,先看代码:
public class Single { public static Single single; private Single(){ } public static Single getInstance(){ if(sing==null){ synchronized (Single.class){ if (single==null) { single=new Single(); } } } return single; } }
10、abstract
抽象类的特色:
1:抽象方法只能定义在抽象类中,抽象类和抽象方法必须由abstract关键字修饰(能够描述类和方法,不能够描述变量)。
2:抽象方法只定义方法声明,并不定义方法实现。
3:抽象类不能够被建立对象(实例化)。
4:只有经过子类继承抽象类并覆盖了抽象类中的全部抽象方法后,该子类才能够实例化。不然,该子类仍是一个抽象类。
十一、String、StringBuffer、StringBuilder区别
因为String类是final修饰的,因此string对象是不可变的,当前它也就是线程安全的。
StringBuffer和StringBuilder都是继承AbstractStringBuilder类,他们都是可变的。
因为StringBuffer对方法或者调用的方法加了同步锁,StringBuilder没有加,因此StringBuilder是非线程安全的,StringBuffer是线程安全的。
在不kao虑多线程的状况下,StringBuilder效率要高于StringBuffer。
十二、==和equals区别
==表示两个对象在内存中存储的值相等,而equals是两个对象的内容相等。
好比:String a=new String("123");String =new String("123");
若是用a==b的话返回false,而a.equals(b)返回true,a和b的内容是相等的,可是a、b是不通的两个对象,他们的首地址是不同的,因此a==b返回false。
1三、JAVA集合类
有时候会有这样的题:请说出几个JAVA经常使用的集合类,他们都有什么区别?
集合你们并不陌生,经常使用的什么ArrayList、map等,下面来介绍一下JAVA的集合类。
总的来讲总共分为两大部分一个是Collection接口,一个是Map接口。
Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set
│├AbstractSet
│├HashSet
│└TreeSet
Map
├Hashtable
├HashMap
└WeakHashMap
先说下Collection,由Collection又派生出两个接口:List和set,二者最大的区别就是list容许有重复元素,set不容许有重复元素;List是有序的,而set除了TreeSet之外,都是无序的。
给定一个字符串(长度不会超过500,必定会有重复的字符),编程返回字符串内第一个重复的字符。例如:“tyuioqiwyss”,返回值:i 。
public static char getFirstRepeat(String str){ HashSet<Object> hs=new HashSet<>(); //定义一个hashset char[] m=str.toCharArray();//将字符串放进一个char数组 for (int i = 0; i < m.length; i++) { boolean b=hs.add(m[i]);//遍历数组元素放进hashset if (!b) { //因为hashset不容许有重复元素,因此当有重复元素被添加的时候就会返回false return m[i]; } } return 0; }
List下面又有ArrayList、LinkedList、Vector和stack,先说下ArrayList、LinkedList的区别:一、ArrayList是基于动态数组的数据结构,对于查找访问操做效率较高;LinkedList是基于链表的数据结构,对于元素的增长删除效率较高。二者都是非同步的。Vector和stack固然就是同步的了,stack继承自Vector,实现了一个后进先出的堆栈。
Set接口是不容许插入重复元素的。
Map的元素是用key,value的形式存储的,能够存入相同的value可是key要保证惟一。
1四、Math
关于math有几个经常使用的方法。
Math.ceil():向上取整 Math.ceil(11.5)=12 Math.ceil(-11.5)=-11
Math.floor():向下取整 Math.floor(11.5)=11 Math.floor(-11.5)=-12
Math.round():四舍五入 Math.round(11.5)=12 Math.round(-11.5)=-11 Math.round(-11.6)=-12
1五、关于异或运算
给定两个Int参数,编程返回两个参数二进制数有多少位不一样。
异或运算是这样的:两位相同则为0,不一样则为1。0000^0011=0011 1001^1100=0101
因此先把给定的两个参数作异或运算,获得的值在判断他的二进制里面有多少1即有多少个不一样的位。
public static int Sample(int m,int n) { int s=m^n; //异或运算 int count=0;//统计1的个数 while (s>0) { s=s&(s-1);//进行与运算,相似移位运算 0&0=0 0&1=0 1&1=1 1&0=0 count++; } return count; }
1六、面向对象的特色,说说对他们的理解。
封装:可使程序实现“高内聚,低耦合”,对象是封装的最基本单位。
继承:提升软件的可重用性和可扩展性
抽象:把某些具备相同特征的事物抽象成一个具体的类,只关心咱们须要的地方
多态:增长软件的灵活性和可扩展性
1七、列举常见的异常及可能产生缘由,异常解决方法?
NullPointerException 空指针异常 简单地说就是调用了未经初始化的对象或者是不存在的对象,好比调用了未初始化对象的方法
ArrayIndexOutOfBoundsException 数组越界 调用的数组长度与实际数组长度不一致,好比一个数组有3个元素,获取第四个元素时就会出现这个异常,因此最好先查看一下数组长度。
NumberFormatException 数字强转异常 常见于把一个字符串转为Int 类型是,Intenger.parseInt("123#")就会抛出异常。
ClassCastException 数据类型转换异常 如用户在输入日期的时候只输入月、日信息,而没有年份的信息。此时应用程序在进行数据类型转换的时候,就会出现异常。
IllegalArgumentException 方法的参数错误 好比g.setColor(int red,int green,int blue)这个方法中的三个值,若是有超过255的也会出现这个异常,所以一旦发现这个异常,咱们要作的,就是赶忙去检查一下方法调用中的参数传递是否是出现了错误。
异常的处理一般咱们使用try catch来处理可能出现的异常,固然咱们应该是捕获这个异常来处理。下面是有关异常处理的几个关键字:
throws 捕获并向外抛出异常
throw 抛出异常
try catch 内部捕获异常并作自定义处理
finally 不管是否有异常都会被处理的语句
1八、线程相关
1)实现一个线程
两种方法:继承thread和实现Runnable接口
2)sleep() wait()区别
sleep()是thread类的一个方法,他须要指定一个时间告诉线程暂停指定时间,时间到了继续执行,暂停期间依然占用CPU;wait()是Object类的一个方法,不须要指定时间,想恢复执行的话须要调用notify或者notifyAll方法,暂停期间不会占用CPU资源。
3)同步和异步
若是数据须要在线程间共享,一个线程在读取数据,另外一个线程在插入数据,这个时候就须要保证同步读取。若是一个线程须要调用的方法须要执行很长时间,但其余线程又不须要该线程的数据返回时应该用异步。
4)启动一个线程是调用start()方法,run()方法是线程进入执行状态所执行的方法。
1九、输入输出流
JAVA的输入输出流有两种 字节流和字符流。字节流继承InputOutStream、OutputStream,字符流继承自InputOutStreamReader、OutputStreamReader。字节流主要操做对象是byte,字符流主要操做对象是字符或者字符串。
字节流在操做的时候自己是不会用到缓冲区(内存)的,是与文件自己直接操做的,而字符流在操做的时候是使用到缓冲区的
字节流在操做文件时,即便不关闭资源(close方法),文件也能输出,可是若是字符流不使用close方法的话,则不会输出任何内容,说明字符流用的是缓冲区,而且可使用flush方法强制进行刷新缓冲区,这时才能在不close的状况下输出内容。
20、内存溢出和内存泄漏(主要针对Android中的状况进行分析)
内存溢出:应用使用的内存大于机器的最大内存。
内存泄漏:cursor使用完了没有关闭;Bitmap没有回收;构造Adapter时,没有使用 convertView
2一、抽象类和接口的区别
一、抽象类能够有成员变量,接口里通常没有。若是有的话默认必须是static final类型的。
二、一个类能够实现多个接口但只能继承一个抽象类
三、抽象类里面能够有非抽象的方法,接口里面的方法都是抽象的,也就是实现他的类里面必须实现他的方法。
四、抽象类中的抽象方法的访问类型能够是public、protected或者包访问类型。而接口中的抽象方法只能是public abstract类型,接口的方法前面能够不加修饰符,默认就是public abstract类型。
2二、java中静态属性、静态代码块、非静态属性、非静态代码块、构造函数在new的时候执行顺序是怎样的?
对于没有继承其余类的执行顺序是这样的:
静态属性--静态代码块--非静态属性--非静态代码块--构造函数
若是继承了其余类:
父类的公共静态属性和静态代码块--自身的静态属性和静态代码块--父类的非静态属性和非静态代码块--父类的构造函数--自身的非静态属性和非静态代码块--自身的构造函数
2三、什么是编译型语言,什么是解释型语言?JAVA属于哪种?
编译型语言是指程序在执行前须要有一个单独的编译过程,将程序翻译成机器语言,之后执行这个程序的时候,就不用再进行翻译了。
解释型语言是指是每次在运行的时候将程序翻译成机器语言,因此运行速度相对于编译型语言要慢。
C/C++ 等都是编译型语言,而Java,C#,脚本语言等都是解释型语言。
虽然Java程序在运行以前也有一个编译过程,可是并非将程序编译成机器语言,而是将它编译成字节码(能够理解为一个中间语言)。
在运行的时候,由JVM将字节码再翻译成机器语言。
2四、经常使用的设计模式有哪些?
单例模式、工厂模式、观察者设计模式、适配器模式等。
2五、synchronized修饰静态方法和非静态方法的区别
synchronized在静态方法上表示调用前要得到类的锁,而在非静态方法上表示调用此方法前要得到对象的锁。
public class StaticSynDemo { private static String a="test"; //等同于方法print2 public synchronized void print1(String b){ //调用前要取得StaticSynDemo实例化后对象的锁 System.out.println(b+a); } public void print2(String b){ synchronized (this) {//取得StaticSynDemo实例化后对象的锁 System.out.println(b+a); } } //等同于方法print4 public synchronized static void print3(String b){//调用前要取得StaticSynDemo.class类的锁 System.out.println(b+a); } public static void print4(String b){ synchronized (StaticSynDemo.class) { //取得StaticSynDemo.class类的锁 System.out.println(b+a); } } }