JAVA基础学习总结(不定期更新)

一、java语法基础

1、final

关于final的问题我曾经被问到两次,所以首先说一下这个东西。

应用于变量,表示该变量一旦被赋值则不可以改变,但是有一个特殊的:StringBuffer,看下面一个例子

final StringBuffer sb=new StringBuffer("123");

这样写 sb=new StringBuffer("");会报错,但是sb.append("111");不会报错。

final是指引用变量不能变,但变量的内容是不可以改变的。StringBuffer 只是有这样一个方法可以改变它的内容而已。

应用于方法,表示该方法不可以被重写覆盖。

应用与类,表示该类不可以被继承。

2、关于private,public,protected,friendly

可以用一个表格说明他们的权限和访问范围,当修饰元素没有修饰符时默认是friendly

- 表示不支持 √ 表示支持

修饰符 当前类 同一包 子孙类 其他包
public
protected -
friendly - -
private - - -

3、基本数据类型

byte、int、short、double、float、long、double、boolean

级别从低到高为byte,char,short(这三个平级)-->int-->float-->long-->double

由低级到高级系统会自动转换,由高级到低级需要强制转换。

4、运算符

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*8、等价于2左移3位

5、Override和Overload的区别(重写和重载区别)。

重载是指同一个类中可以存在多个命名相同的方法,但是各个方法的参数个数或类型必须不同,并且不可以通过改变方法的返回值来表示两个方法的不通。

重写是指子类可以与父类的方法名称参数相同,等于完全把父类的方法覆盖了。但是对于异常,子类的方法必须比父类抛出更少的异常或者是父类异常的子异常。

6、java内存

java内存大概分为5块:寄存器,本地方法区,方法区,堆,栈。

栈:主要用来存储局部变量,当运算完成所在趋于结束,内存将被释放。

堆:存储数组和对象。

7、成员变量和局部变量区别

成员变量在类里面定义,只在类里面有效;局部变量存在方法中定义,只在方法所在的大括号有效。

成员变量存在于堆内存中;局部变量存在与栈内存中

8、this 和 super

this 通常用来表示对象本身,super访问父类被子类隐藏的变量或覆盖的方法。

如果一个类继承自父类,那么子类的super()方法即对父类的初始化。当类中有两个同名变量,一个属于类(类的成员变量),而另一个属于某个特定的方法(方法中的局部变量),使用this区分成员变量和局部变量。

调用super()必须写在子类构造方法的第一行,否则编译不通过。每个子类构造方法的第一条语句,都是隐含地调用super(),如果父类没有这种形式的构造函数,那么在编译的时候就会报错。

super()和this()类似,区别是super从子类中调用父类的构造方法this()在同一类内调用其它方法。

super的本质是java的一个关键字,this的本质是一个指向本对象的指针。

9、单例模式

保证一个类在内存中的对象中唯一性。

步骤:1、私有化构造函数。2、创建一个静态的私有的本类对象。3、提供一个对外调用的方法

单例模式的创建有两种:懒汉式,饿汉式

首先来看下懒汉式:

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;   
}
}

10abstract 

抽象类的特点:

1:抽象方法只能定义在抽象类中,抽象类和抽象方法必须由abstract关键字修饰(可以描述类和方法,不可以描述变量)。

2:抽象方法只定义方法声明,并不定义方法实现。

3:抽象类不可以被创建对象(实例化)。

4:只有通过子类继承抽象类并覆盖了抽象类中的所有抽象方法后,该子类才可以实例化。否则,该子类还是一个抽象类。

11、String、StringBuffer、StringBuilder区别

由于String类是final修饰的,所以string对象是不可变的,当前它也就是线程安全的。

StringBuffer和StringBuilder都是继承AbstractStringBuilder类,他们都是可变的。

由于StringBuffer对方法或者调用的方法加了同步锁,StringBuilder没有加,所以StringBuilder是非线程安全的,StringBuffer是线程安全的。

在不kao虑多线程的情况下,StringBuilder效率要高于StringBuffer。

12、==和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。

13、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下面又有ArrayListLinkedList、Vector和stack,先说下ArrayListLinkedList的区别:1、ArrayList是基于动态数组的数据结构,对于查找访问操作效率较高;LinkedList是基于链表的数据结构,对于元素的增加删除效率较高。两者都是非同步的。Vector和stack当然就是同步的了,stack继承自Vector,实现了一个后进先出的堆栈。

Set接口是不允许插入重复元素的。

Map的元素是用key,value的形式存储的,可以存入相同的value但是key要保证唯一。

14、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

15、关于异或运算

给定两个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;
  
 }

 

16、面向对象的特点,说说对他们的理解。

封装:可以使程序实现“高内聚,低耦合”,对象是封装的最基本单位。

继承:提高软件的可重用性和可扩展性

抽象:把某些具有相同特征的事物抽象成一个具体的类,只关心我们需要的地方

多态:增加软件的灵活性和可扩展性

17、列举常见的异常及可能产生原因,异常解决方法?

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 无论是否有异常都会被处理的语句

18、线程相关

1)实现一个线程

两种方法:继承thread和实现Runnable接口

2)sleep() wait()区别

sleep()是thread类的一个方法,他需要指定一个时间告诉线程暂停指定时间,时间到了继续执行,暂停期间依然占用CPU;wait()是Object类的一个方法,不需要指定时间,想恢复执行的话需要调用notify或者notifyAll方法,暂停期间不会占用CPU资源。

3)同步和异步

如果数据需要在线程间共享,一个线程在读取数据,另一个线程在插入数据,这个时候就需要保证同步读取。如果一个线程需要调用的方法需要执行很长时间,但其他线程又不需要该线程的数据返回时应该用异步。

4)启动一个线程是调用start()方法,run()方法是线程进入执行状态所执行的方法。

19、输入输出流

JAVA的输入输出流有两种 字节流和字符流。字节流继承InputOutStream、OutputStream,字符流继承自InputOutStreamReader、OutputStreamReader。字节流主要操作对象是byte,字符流主要操作对象是字符或者字符串。

字节流在操作的时候本身是不会用到缓冲区(内存)的,是与文件本身直接操作的,而字符流在操作的时候是使用到缓冲区的

字节流在操作文件时,即使不关闭资源(close方法),文件也能输出,但是如果字符流不使用close方法的话,则不会输出任何内容,说明字符流用的是缓冲区,并且可以使用flush方法强制进行刷新缓冲区,这时才能在不close的情况下输出内容。

20、内存溢出和内存泄漏(主要针对Android中的情况进行分析)

内存溢出:应用使用的内存大于机器的最大内存。
内存泄漏:cursor使用完了没有关闭;Bitmap没有回收;构造Adapter时,没有使用 convertView

21、抽象类和接口的区别

1、抽象类可以有成员变量,接口里一般没有。如果有的话默认必须是static final类型的。

2、一个类可以实现多个接口但只能继承一个抽象类

3、抽象类里面可以有非抽象的方法,接口里面的方法都是抽象的,也就是实现他的类里面必须实现他的方法。

4、抽象类中的抽象方法的访问类型可以是public、protected或者包访问类型。而接口中的抽象方法只能是public abstract类型,接口的方法前面可以不加修饰符,默认就是public abstract类型。

22、java中静态属性、静态代码块、非静态属性、非静态代码块、构造函数在new的时候执行顺序是怎样的?

对于没有继承其他类的执行顺序是这样的:

静态属性--静态代码块--非静态属性--非静态代码块--构造函数

如果继承了其他类:

父类的公共静态属性和静态代码块--自身的静态属性和静态代码块--父类的非静态属性和非静态代码块--父类的构造函数--自身的非静态属性和非静态代码块--自身的构造函数

 

 

 

你可能感兴趣的:(JAVA基础学习总结(不定期更新))