1,java中的循环语句有哪些,判断语句有哪些;
答:while循环,do-while循环,for循环
2,this关键字和super关键字的区别
答:this是一个指向自身的指针;super是一个指向父类的指针。
都是作为参数传给定义的方法中默认并且隐藏的。this关键字指向本类中的方法或者成员属性。
super关键字在子类继承父类的属性或方法时使用。
3,进程和线程的区别
进程:是一个正在执行中的程序,每一个进程都有一个执行顺序,该顺序叫做执行路径或者控制单元。
线程:是进程中一个独立的控制单元,控制着进程的执行,一个进程至少有一个线程。
4,死锁产生的原因
答:原因有三个:1,系统资源不足。2,进程运行推进的顺序不合适。3,资源分配不当。
产生死锁的四个必要条件:1,互斥条件:一个资源每次只能被一个进程使用。
2,请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源不放
3,不剥夺条件:进程已获得的资源,在未使用完之前不强行剥夺,
4,循环等待条件:若干进程形成一种头尾相接的循环等待资源关系。
5,抽象类和接口的区别
答:1,抽象类只能被继承,而且是单继承;接口需要被实现,可以多实现。
2,抽象类中可以定义非抽象方法,子类直接继承使用;接口中的所有方法必须都是抽象方法,需要子类去实现。
3,抽象类中的成员修饰符可以自定义,接口中的成员修饰符都是public的。
6,谈谈对面向对象的理解,并举例说明
答:java中面向对象有三大特征:继承,封装和多态。
1,封装就是将一个事物一个对象的属性和实现细节隐藏起来,只对外提供公共的访问方式。封装的好处就是提高了复用性,安全性,便于使用,将变化分离。单例设计模式就是封装很好的体现。
2,继承子类可以继承父类所有非私有的成员方法和属性,子类也可以扩展父类的功能,覆盖父类中除final修饰的方法等。比如人是一个类,女人这个类继承了人,拥有人这个类的所有功能,又有自己一些独特的地方。
3,多态。类的多态性其实就是一个对象的某项功能可以处理不同类型的问题,父类引用或者接口引用指向子类对象。比如说重载和覆盖就是多态的体现。
7,final,finally,finalize的区别
(在这里面特别是在静态方法中访问非静态方法中的变量,具体怎么做,要自己总结说出来)finalize方法是java提供的进行资源清理的机制。
答:final是Java中的一个类型修饰符,可以修饰类,变量,成员方法等。被final修饰的类为最终类不能被继承,被final修饰的变量为常量不能被重写,被final修饰的方法为最终方法不能被覆盖。
finally,在java异常处理机制中的一种,finally块中的代码一定会被执行,一般存放关闭资源等需要一定被执行的代码。
finallize()方法java中提供的默认清理对象资源的一种机制。
8,冒泡排序和选择排序的实现
冒泡排序的特点:相邻两个元素进行比较,如果符合条件则换位。
冒泡排序:相邻的两个元素进行比较,如果符合条件换位。这样比完第一圈之后,
数组中的最大元素被换到了数组的最后位置。第二圈比较除它之外的其他元素,第三圈,则比较去掉数组最后两个位置的其他元素。
public static void bubbleSort(int[] arr)
{
//如果是末尾元素,不用比
for(int i=0;i<arr.length-1;i++)
{
for(int j=0;j<arr.length-i-1;j++)//减i,是让每一圈比较的元素减少,即不用再比较每一圈的最大值;减1,是防止角标越界,因为for循环中有j角标元素和j+1角标元素的比较,很容易越界
{
//相邻位置比较,如果前一个比后一个大,则将较小的移到前边
if(arr[j]>arr[j+1]) //这是从小到大排序,如果想要从大到小,则将>换成<即可。
{
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
}
选择排序:从0角标的元素与其余元素分别比较,将较小的元素替换到0角标位置。比完之后,再以同样的方式将1角标的元素与其他元素分别比较,以此类推。直到比完
public static void selectSort(int [] arr)
{
for(int i=0;i<arr.length-1;i++)
{
for(int j=i+1;j<arr.length;j++)
if(arr[i]>arr[j])
{
int pot=arr[i];
arr[i]=arr[j];
arr[j]=pot;
}
}
}
9,在静态方法中访问非静态方法中的变
答:静态方法是不能访问非静态变量的。因为非静态变量是在创建对象之后才存在与内存中的,而静态方法属于类本身,在类被加载时就会分配内存。他俩产生时间不同静态方法先产生,所以不能访问非静态变量。
10,重载和覆盖的区别
答:1,重载是在一个类中,方法名相同,但参数列表不同的方法之间称为重载。这里的参数列表不同是指参数类型,个数,序列不同。与方法的返回值类型,修饰符等无关。
2,覆盖是在两个类中。比如子类可以覆盖父类中的非私有的方法,还比如实现接口时覆盖接口中所有的抽象方法。覆盖应注意覆盖方法与被覆盖的方法两者标志必须完全相同,返回值相同,抛出的异常也要一致,或是其子类。
11,静态代码块,还有静态的作用,静态代码块的特点:随着类的加载而执行,并且只运行一次,用于给类初始化
答:静态代码块不包含在任何方法体中,就和在变量之前加static修饰符作用一样。静态代码块的特点:随着类的加载而执行,并且只运行一次,用于给类初始化。
12,内部类(这个面试比较重要)
答:java中的内部类有静态内部类,成员内部类,局部内部类和匿名内部类。
静态内部类:可以访问外部类所有的静态成员和方法,不能访问非静态的。
成员内部类:相当于成员方法。只有创建了外部类对象才能创建成员内部类。创建方式:Outer out=new Outer(); Outer.Inner in=out.new Inner();
局部内部类:存在于某个方法的类。与局部变量类似,其声明和实例化对象都在方法体中。访问包含自身的方法的变量和形参时,需要声明为final。
匿名内部类:没有明字的内部类。就是一个匿名的子类对象。跟在实例化接口或实例化抽象类后边,表示实现接口或继承抽象类。其花括号中要实现所有抽象的方法。如果是实现接口,那个接口中的抽象方法最好不要多余三个。
13,多线程,如何实现多线程,如何开启多线程;
答:实现多线程的方式有两种:
第一种是继承Thread类,步骤:1,写一个类继承Thread类2,重写Thread类中的run方法,将需要被多线程执行的代码存放到run方法中。3,创建该类对象,调用start方法,开启线程并执行重写的run方法。
第二种是实现Runnable接口,步骤:1,写一个类实现Runnable接口2,覆盖Runnable接口中的run方法。3,通过Thread类创建线程对象,将实现了Runnable接口的类作为实际参数传递给Thread类的构造函数。4,调用Thread类对象的start方法,开启线程,并调用Runnable接口中实现的run方法。
这两种方式的区别:
实现Runable接口的方式避免了java中单继承的局限性。
还有就是二者存放线程代码的位置不同,继承方式存放在Thread子类的run方法中,实现方式存放在实现Runable接口的子类对象中。
14,单例的设计模式作用,懒汉式和饿汉式的区别
答:单例设计模式的作用就是保证一个类的对象在内存中的唯一性。它有两种方式懒汉式和饿汉式。这两种方式的区别:
懒汉式主要用于对实例的延迟加载。懒汉式会有安全性问题,会出现被多个线程创建对象的结果。解决方式:加同步代码块synchronized或者同步函数的方法,但效率比较低,可以加同步代码块同时使用双重判断。同步代码快使用的锁为本类的字节码。
15,集合和数组都是容器他们有什么不同?
答:集合只用于存储对象,其长度是可变的。
数组也可以存储对象,但主要用于存储基本数据类型,其长度是不可变的。
16,集合框架(介绍完后还要说出map遍历的实例,有哪几种)
答:集合的两大父类接口是Collection和Map。
首先说Collection接口,它有两个子接口List和Set。List集合的特点是元素有序,元素可以重复,该集合体有索引。Set集合的特点是元素无序,元素不可以重复。
List集合的常见子类是ArrayList和LinkedList。其中ArrayList底层的数据结构是数组数据结构,其特点是查询较快,增删较慢。而LinkedList底层的数据结构是链表数据结构,其特点是查询较慢,增删较快。还有一个子类Vector已经被ArrayList替代,它是线程同步的查询很慢。
Set集合常见的子类有HashSet和TreeSet。HashSet集合的底层的数据结构是哈希表,线程非同步。TreeSet底层数据结构是二叉树,默认排序是从小到大的。
接下来说一下Map集合。该集合存储的不再是单个元素而是键值对,一对一对往里存,而且保证键的唯一性。
Map接口的常见子类有HashMap和TreeMap。HashMap底层是哈希表数据结构,线程非同步。可以存储null键,null值。TreeMap底层是二叉树数据结构,线程非同步。可以对Map集合中的键值进行指定顺序的排序。
Map集合的取出方式有两种:一种是通过keySet方法,获取到map集合中的所有键将其存放到set集合中,因为Set集合具有迭代器,所以可以用迭代器迭代出所有的键值,再根据map集合中的get方法获取到所对应的所有值。
另一种entrySet方法是将map集合中的所有键值对存放到泛型类型为Map<Entry<,>>的Set集合中,在迭代时,Map<Entry<,>>的getKey和getValue方法直接获取键和值。
17,在进行list列表元素迭代的时候,如果想要在迭代过程中,想要对元素进行操作的时候,比如满足条件添加新元素。会发生.ConcurrentModificationException并发修改异常。发生此异常的原因是什么,应该如何改进?
答:发生此异常的原因是集合引用和迭代器引用在同时操作元素,通过集合引用获得对应的迭代器后,在迭代时,再用集合的方法对元素进行添加,迭代器并不知道。所以会发生兵法修改异常。
解决方法:迭代时使用Iterator的子类ListIterator,该迭代器具有对List集合的元素进行增删改查的动作。
18,List集合判断元素是否相同的依据是什么,Set集合又是如何保证元素唯一性的?
答:List集合判断元素是否相同的依据是euqals方法,集合的contains方法和remove方法等都在底层调用了equals方法。如果List集合中添加的是是一个自定义的对象根据需要可重写equals方法。
Set集合中HashSet和TreeSet保证唯一性的原理是不同的。
HashSet保证唯一性,依据的是hashCode和equals两个方法。这两个方法都是在底层内部调用的,当有元素存入哈希表时,首先调用hashCode方法,来计算该元素的哈希值,如果哈希值不同则直接存入。如果哈希值相同,则再调用equals方法判断元素是否相同,如果不同则在哈希表的同一位置上顺延,如果相同则不存入。注意的是,HashSet对于元素的删除,判断是否存在等操作,首先依赖的是hashCode方法,其次是equals方法。
而TreeSet集合保证唯一性的依据是:compareTo方法的如果返回值为0,则是两个对象重复,不存。
19,哈希表的原理
答:1,对对象元素的关键字进行哈希算法的运算,得出的值就是哈希值。2,这个哈希值就是对象的存储位置。3,如果哈希值有冲突,则再调用equals方法判断元素是否相同,如果相同则不存,如果不同则在同一位置上顺延。4,存储哈希值的结构就是哈希表。5,应该尽量保证元素的关键字的唯一性,这样可以减少判断哈希值对应的元素是否相同,提高哈希表的操作效率。
20,TreeSet的排序方式有哪几种?
答:有两种:一种是通过Comparable接口,一种是通过Comparator接口。
第一种:让元素自身具备比较性,实现Comparable接口,覆盖comparaTo方法。这种方式也成为默认排序。如果想要按照存储的顺序将元素取出,只需在comparaTo方法中写return 1;即可。如果想要按照存储的顺序逆序取出,写return -1;即可。
第二种:让集合自身具备比较性,需要定义一个实现Comparator接口的比较器,覆盖compare方法。并将该对象作为参数传递给TreeSet集合的构造方法。当两种排序方式都存在时,以比较器为主。
21,JDK1.5出现的新特性有哪些?
答:1,增强for循环。
2,自动装箱拆箱 。享元模式,有很多小的对象它们有一些共同的属性,把这些小的对象变成一个对象。其共同属性称为内部状态,不同属性变成方法的参数,称为外部状态。
3,可变参数。数组的简写形式,将元素作为参数传入即可,隐式的将这些参数封装成数组。可变参数只能出现在参数列表的最后。
4,静态导入 import static 导入一个类的静态方法
5,泛型。Jdk1.5版本以后出现的一个安全机制。它的好处是:
第一,将运行时期的ClassCastException异常,转到编译时期,方便程序员调试,解决问题
第二,避免了强制转换的问题。
泛型技术其实应用在编译时期,主要给编译器使用,到了运行时期,泛型就不存在了,可以限定集合的输入类型。这是因为泛型的擦除,即在编译时期检验了类型的正确后,运行生成的字节码文件不包含泛型。运行时如何知道元素的类型而不用强制转换?因为泛型的补偿,因为编译时已经确定了元素的类型,运行时只要和获取到元素的类型内部转换以下即可。
Array集合规定好的泛型是integer的,想往里面传入string类型,应该如何实现。
答:因为泛型在字节码文件中是不存在的,所以可以通过反射的方式获得该集合的class实例对象,再获得其add方法,调用它,添加string类型的数据即。
6,枚举,关键词enum。用枚举定义变量时,只能是枚举里的元素。
枚举中的构造方法必须在所有枚举元素列表之后。枚举中可以定义抽象方法,在声明枚举元素时,可以通过内部类的形式实现该抽象方法。
22,拷贝mp3,拷贝文件和文件夹的具体实现方法
(在这里还问到了,字符流能不能用于对图片的操作,是不可以的。具体原因视频上都有, 要用自己的话进行总结)
答:拷贝mp3的具体实现方式步骤:
分析首先mp3不是纯文本,所以应该使用字节流。
1,创建一个FileInputStream 对象与要复制的mp3文件相关联。
2,创建一个FileOutputStream对象,同时明确要写入的文件的名称。
3,创建一字节数组
4,字节数组不断的读写完成mp3文件的拷贝
5,关闭流资源。
拷贝文件夹,这个文件夹中的内容有很多种情况,可能既有纯文本又有其他格式的文件,所以首先应该确定使用字节流进行复制。其次,这个文件夹下可能还有子文件夹,所以应该使用递归。那么具体的步骤,
1,将该文件夹的路径封装成File对象
2,使用listFile方法获得该文件夹下的所有内容
3,使用for‘循环遍历File[]数组,判断得到的file[x]是否是文件如果是文件按照字节流的方式复制。判断是否是目录,如果是则递归调用本函数即可。
23,.IO流里面的读写操作,字符流复制文件、字节流复制文件、复制文件夹的区别,用转换流举例说明(对于接口能不能是Object的子类)
答:复制过程不同:
字符流的复制要经过io流向字符的转化的解码过程,解码完成后,再进行逆过程的编码形成输出io流,最终写入目标io流
字节流的复制,不必关注复制的内容,数据直接以字节的形式进性传输,不必编码解码
文件夹的复制,相对比较复杂,一般要使用递归遍历里面的目录,有文件夹的创建文件夹,是文件的用字节流复制。
24,.动态代理(这里要说出动态代理具体实现,两种实现方法)
(动态代理和普通代理的区别)
答:动态代理:JVM在运行期动态生成出类的字节码,这种动态生成的类往往被用作代理类,通常称为动态代理类。JVM生成的动态类必须实现一个或多个接口,所以这个动态类只能用作具有相同接口的目标类的代理。
( 静态代理通常只代理一个类,动态代理是代理一个接口下的多个实现类。
静态代理事先知道要代理的是什么,而动态代理不知道要代理什么东西,只有在运行时才知道。)
动态代理的具体实现方式:第一种方式,首先获得其构造方法。然后写一个类实现InvocationHandler接口,在newInstance方法中传入该类对象。
//然后通过构造方法创建动态类的实例
Collection proxy1=(Collection)constructor.newInstance(new MyInvocationHandler());
第二种方式:也是首先得到其构造方法,通过匿名内部类完成
//第二种方式,通过内部匿名类完成
Collection proxy2=(Collection)constructor.newInstance(new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
return null;
}
});
第三种方式://第三种方式,通过Proxy类的newProxyInstance一步到位
Collection proxy3=(Collection)Proxy.newProxyInstance(
Collection.class.getClassLoader(),
new Class[]{Collection.class},//不能使用可变参数因为它不是最后一个参数
new InvocationHandler(){
//将下面这句话添加到方法前作为成员变量,下面的size方法打印结果不再是0而是3
ArrayList target=new ArrayList();
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//给这个代理对象指定目标
//ArrayList target=new ArrayList();
long beginTime=System.currentTimeMillis();
Object retVal=method.invoke(target, args);
long endTime=System.currentTimeMillis();
System.out.println(method.getName()+"运行时间:"+(endTime-beginTime));
return retVal;
}
});
25,什么是递归
答:递归就是函数自身调用自身,只不过传入的参数不同
19.反射及暴力反射 ,获得私有方法代码(这里用到反射)
(反射题:总结反射机制,反射一般用在什么地方,通过反射一般可以获得什么
)
答:反射就是把java类中的各种成分映射成相应的类。获取字节码对应的实例对象即class类的实例对象的三种方式:
1,类名.class 2,对象名.getClass() 3,Class.forName(“完整的类名”);
反射机制的优点就是可以实现动态创建对象和编译,具有很大的灵活性,体现了多态的应用。一般用来加载类的实例,成员属性,方法等,运行时可以获得对象的信息。
暴力反射:通过反射获得一些私有属性或方法后并没有使用权限,通过setAccessible(true);方法暴力获得权限,这称为暴力反射
26,类加载器及其委托机制
答:类加载器将一个类的字节码文件加载到内存中,并做一些处理,这就是类加载器的作用。Java虚拟机可以安装多个类加载器,系统默认的三个主要的类加载器有,BootStrap,ExitClassLoader,AppClassLoader。BootStrsp是根加载器,他不是java类。
类加载器的委托机制:
第一,首先当前线程的类加载器去加载线程中的第一个类
第二,如果类A中引用了类B,java虚拟机使用加载类A的类加载器去加载类B
第三,还可以调用ClassLoader类的classLoader方法指定某个类加载器去加载某个类。每个类加载器加载时,又会委托给其上级类加载器,当所有祖宗类加载器没有加载到该类时,就会回到发起者类加载器,还加不了,就抛出ClassNotFoundException异常。并不再找发起者类加载器的儿子。
27,配置环境变量的时候,为什么需要配置path和classpath
答:配置path的作用是,当我们在控制台输入javac HellowWorld.java时,系统可以明白到哪里去找javac,java命令
配置classpath的作用是:当我们运行javac,java命令时,系统可以知道到哪里去找Java程序的源文件及其字节码文件。
28,continue,return,break介绍这三个的具体用法,用于什么情况下
答:break语句会使运行的程序立刻退出最内层循环或退出一个switch语句。
Continue语句与break类似,但是它不是退出循环,而是开始循环新一次的迭代。用在while,do/while,for语句中
return用于指定函数的返回值。只能出现在函数体内
29,栈和堆的区别(这里最好总结全面一点)
答:Java把内存分为堆内存和栈内存
栈内存:在函数中定义的一些基本类型的变量和对象的引用变量都是在栈内存重分配,当在代码中定义一个变量时,java就在占内存中为这个变量分配内存空间,当超过变量的作用域后,java自动释放该变量的内存空间。
堆内存:用来存放new创建的对象和数组,在堆中分配的内存,由java虚拟机的自动垃圾回收机制来管理。引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到其作用域之外后被释放。而数组和对象本身在堆中分配,即使程序运行到使用 new 产生数组或者对象的语句所在的代码块之外,数组和对象本身占据的内存不会被释放,数组和对象在没有引用变量指向它的时候,才变为垃圾,不能在被使用,但仍 然占据内存空间不放,在随后的一个不确定的时间被垃圾回收器收走(释放掉
,