java面试问答

    xiaoxiao2023-03-24  2

    1:JDK与JRE JDK:JAVA Development Kit, java开发工具包; 包括各种类库和工具,当然也包括JRE JRE:JAVA Runtime Environment,java程序运行环境,包括JAVA类库的class文件和JVM

    2:JAVA_HOME PATH CLASSPATH JAVA_HOME :JDK的安装目录,很多web服务器如tomcat没有内置JDK,它们通过JAVA_HOME找到JDK PATH:在原有值后加“;%JAVA_HOME%\bin”;通过配置PATH,可以再任何命令提示符窗口中使用JAVAC、JAVA等命令了 CLASSPATH:用来指定JAVA程序搜索类的路径的,JAVA程序在编译和运行时,先搜索jre/lib/rt.jar中的类,然后搜索CLASSPATH中指定的类;一般CLASSPATH会包括当前目录“.”

    3:JAVA程序动态的指定类搜索路径方法 利用-cp或-classpath选项,如 javac –cp D:\wrok\log4j.jar Hello.java (编译时指定D:\wrok\log4j.jar为搜索路径) java –cp D:\wrok\log4j.jar Hello

    4:JAVA和C++程序在编译及运行上的区别 C,C++这类语言的编译器(例如 UNIX下的CC命令,WINDOWS下的CL命令)都是把源代码直接编译成计算机可以认识的机器码,如EXE、DLL之类的文件,然后直接运行。 JAVA为了实现跨平台,多了一个中间步骤,就是先生成字节码文件,javac命令先把源文件编译成计算机无法直接识别的class文件,但是它可以被JVM所认识,JVM有多个平台版本,因此可以在多个平台执行。

    5:什么是JVM及其工作原理 JVM是一个想象中的机器,在实际的计算机上通过软件模拟来实现。Java虚拟机有自己想象中的硬件,如处理器、堆栈、寄存器,还有相应的指令系统。JVM在执行字节码时,把字节码解释成具体平台上的机器指令执行。

    6:JAVA垃圾回收机制 JVM中栈存放的是非static的自动变量、函数参数、表达式的临时结果和函数返回值。栈中这些实体数据的分配和释放均是由系统自动完成的。 堆中存放的实体数据是程序员显示分配的(new),没有自动垃圾回收机制的系统中(有些JVM没有垃圾回收机制)必须显示的释放这些实体 C、C++中也有栈和堆,对堆的管理,C是通过malloc()和free();而C++是通过new和delete

    Object对象中有个finalize(),它会在对象被回收之前被调用; System.gc();和Runtime.getRunime().gc()两个方法都可以显示请求开始垃圾回收线程

    7:jar和war 两者都是java可执行文件,jar是对于桌面应用程序,war是对于web应用程序; Jar和war打包都通过JDK的jar命令

    8:JAVA变量及作用范围 分为:静态变量、成员变量、局部变量 静态变量在类中用static修饰,生存周期由类决定;成员变量是类中没有用static修饰的变量,生存周期有对象来决定;局部变量是定义在方法里的变量、方法的参数、代码块里的变量,它们的作用范围用大括号{}来界定

    9:JAVA变量分为哪两种大的数据类型 基本数据类型和引用数据类型 ,它们最大的区别在于引用数据类型存放的是数据所在的地址,而基本数据类型直接存放数据的值;二者都保存在栈中

    10:装箱、拆箱指的是基本基本数据类型和包装类型的自动相互转化

    11:C++指针和JAVA引用的区别 相同:都是指向一块内存地址 不同: 一 类型转换:引用的类型转换,可能抛出java.lang.ClassCastException,引用对应的类型不同的话,转换不成功;C++指针则一定能转换成功,指向哪儿,还是一个地址 二 初始值:引用类型的初始值为null;C++指针是int,如不初始化,值是随机的 三 计算:引用不可计算;指针可计算,如++或— 四 内存泄露:JAVA引用基本不会产生内存泄露;指针容易,程序员须及时回收 五 作为参数:JAVA方法本质上只有传值,引用作为参数使用时,回给函数内引用的COPY,所以在函数内交换两个引用参数是没意义的,但改变一个引用参数的属性是有意义的,因为引用参数的COPY所引用的对象和引用参数是同一个对象; C++指针作为参数,实际上就是它所指的地址在函数中被操作。

    12:equals()和== ==运用在基本数据类型是比较的是实际的值;用于比较引用类型时候,比较两个引用的地址是否相同;(都是比较栈中数据) Object有equals()方法,默认的比较方式与==相同,String类重写了该方法,使其能比较字符串的内容;

    13:JAVA三元运算符 表达式1?表达式2:表达式3 表达式1为true则执行表达式2 ;否则执行表达式3

    14:Java注释类型 ①行注释 // ②块注释 /* ….. */ ③文档注释 /* …. / ④Annotation

    15:类与对象 类是一种抽象,JVM对类只加载一次 对象是类的实现,通过new创建,可以创建多个对象;

    面向对象特性:封装、继承、多态

    16:什么是多态 本质是可发送消息给某个对象,让该对象自行决定响应何种行为。通过将子类对象引用赋值给超类对象引用变量(向上转型)来实现动态方法调用

    17:java中静态成员的特点 类的静态成员是通过static修饰的成员,主要有:静态成员变量、静态方法、静态代码块;它们具有如下特点: ① 在类加载的时候,就进行创建、初始化或执行代码 ② 对于一个类来说,都只有一份 ③ 类的所有实例都能访问到它们

    18:子类调用父类的构造函数 super([args])必须放在子类构造函数的第一行

    19:抽象类和接口的区别 ① 接口中的方法都是抽象方法,不必写abstract ② 接口中的属性为static final 静态不可修改的常量 ③ 最大区别是一个类可以实现多个接口,但只能继承一个抽象类 ④ 抽象类中可以有非抽象方法 面向功能用接口,面向继承用抽象类;如果属性得继承用抽象类;

    20:内部类 成员式:静态内部类和成员内部类 局部式:普通局部内部类和匿名内部类

    ① 静态内部类:相当于外部类的静态成员一样,用static修饰 ,外部类加载时内部类也随之加载,完整类名是abc.Outter.Inner;无法访问外部类的非静态成员 ② 成员内部类:相当于外部类的普通成员一样,没有用static修饰,需等外部类创建了对象以后才会被加载到JVM中;创建成员内部类方法: Outter o = new Outter(); Outter.Inner I = o.new Inner(); ③ 局部内部类:定义在一个方法体中,它往往仅作为方法短暂的使用,只能访问用final 修饰的局部变量 ④ 匿名内部类:也定义在方法体中,但没有一个具体的名字 如: Public void adc(){ new OneInterface(){//OneInterface为一个接口名 … //直接提供具体的实现 } }

    21:int和Integer有什么区别 int 属于8中基本数据类型之一,4字节长度,取值范围:-231~231-1;它保存在栈中;可以用算术运算符进行加、减…;在参数传递时传递的是它的值。 Integer是int的包装类;保存在堆中;不可以用算术运算符进行加、减…(因此得转为int);在参数传递时传递的是它所代表对象的引用。

    int a = 10; Integer b = new Integer(a);//int–Integer Integer c = Integer.valueOf(a);//int-Integer a = b.intValue()+1;//Integer–int

    22:float f = 2.3(错) 2.3默认为double型 float f = 2.3f或float f = (float)2.3

    23:类型转换 隐式转换:由类型字节长度小的向类型字节长度大的转换 如int隐式转换为double 或者是子类对象赋值给父类的引用 显示转换:与上相反 当实型向整型转换时,会出现精度的损失,而且在进行float或double进行计算时会出现奇怪的问题,这时可以用BigDecimal类进行精确计算

    24:用BigDecimal类进行精确计算 BigDecimal提供add() substract() multiply() divide()方法 如: BigDecimal b1 = new BigDecimal(Double.toString(0.2)); BigDecimal b2 = new BigDecimal(Double.toString(0.3)); System.out.println(b1.add(b2).doubleValue());

    25:JAVA不能用0代表false;也不能用非0代表true; 只能用boolean类型的true和false 因此C++中 while(1){…}在JAVA是错的

    26:JAVA中 char类型采用unicode编码格式,用2个字节表示一个字符,范围从0到216-1 char能存储中文,且兼容英文字母(ASCII 0~127)

    27:JAVA对象池 从JDK5.0开始,JVM启动时会实例化9个对象池。这个对象池分别用来存储8中基本类型的包装类对象和String对象。主要是为了效率问题。例子: ①String str1 = “hello”; String str2 = “hello”; ②String str3 = new String(“hello”); System.out.println(str1==str2);//输出true System.out.println(str1==str3);//输出false

    ①处用字符串字面量(双引号),JVM到String对象池中去检查是否有一个值相同的对象,如果有就取现成的对象,如果没有,则创建一个新的对象,并加入到对象池中; ②处直接创建新的字符串,且未加入到对象池

    对象池的简单实现: class Dog{ private String name; private int age; private static HashSetpool = new HashSet(); public static Dog newInstance(String name,int age){ for(Dog dog:pool){ if(dog.name.equals(name)&&dog.age==age) return dog; } //如果对象池中没有,创建并加入对象池 Dog dog = new Dog(String,name); pool.add(dog); return dog; }

    28:StringBuffer和StringBuilder Java字符串String对象有个特性—不变性,它只能被创建,而不能被修改(只要一改变就新创建一个对象);因此,一些大量使用字符串的程序(如字符串拼接)可能会出现性能瓶颈,甚至内存溢出;这时需要用到StringBuffer或StringBuilder,两者API相似,但StringBuilder能保证线程安全。 简单示例: StringBuffer sb = new StringBuffer(); sb.append(“a”); String str = sb.toString();

    29:如何输出反转过后的字符串 方法1:利用字符串存储字符的原理,取出它的char数组,进行重新排列; 方法2:利用StringBuffer的reverse()方法

    30:JAVA数组本质上是一个类,该类保存了数据类型的信息。通过成员变量的形式来保存数据,并且通过[],使用下标来访问这些数据。将基本数据类型初始为各自默认的初始值,如将int初始为0(若程序员未提供初始值),将引用数据类型初始为null

    31:集合 List: 有序,允许重复 Set: 无序,不允许重复 SortedSet: 排好序的Set Map: 键值对 键不可重复 SortedMap: 排好序的Map(根据key排序);

    List和Set是Collection的子类

    32:迭代器 提供一种访问一个集合对象中各个元素的途径,同时又不需要暴露该对象的内部细节。JAVA通过提供Iterable和Iterator两个接口来实现集合类的可迭代性。从JAVA5.0开始,迭代器可以被foreach循环所替代,但是foreach循环的本质就是使用Iterator进行遍历的。

    33:比较器 方法1:要比较的自定义类实现Comparable接口,实现其compareTo(Object o)方法 方法2:定义比较器,实现Comparator接口,实现compare(Object o1,Object o2)方法 String类实现了Comparable,用方法1实现了比较 Collections.sort(Collections c,Comparator com)//这时用方法2定义比较器传入sort方法 Collections.sort(Collections c)//这时用方法1

    示例1: public class Person { private String name; private int age; public Person(String name,int age){ this.name = name; this.age = age; } ………setters and getters… }

    public class CompareByName implements Comparator{ public int compare(Object o1, Object o2) { Person p1=null; Person p2=null; if(o1 instanceof Person&&o2 instanceof Person){ p1 = (Person)o1; p2 = (Person)o2; }

    /* if(p1.getName().compareToIgnoreCase(p2.getName())>0){ return 1; } if(p1.getName().compareToIgnoreCase(p2.getName())<0){ return -1; } return 0;*/ return (p1.getName()).compareTo(p2.getName());

    }

    public class DemoPerson { public static void main(String[] args) { Person p1 = new Person(“c”,24); Person p2 = new Person(“b”,8); Person p3 = new Person(“a”,34);

    List<Person> list = new ArrayList<Person>(); list.add(p1); list.add(p2); list.add(p3); //未排序之前 for(Person p:list){ System.out.println(p.getName()+":"+p.getAge()); } //按年龄排序之后 System.out.println("按年龄排序之后"); Collections.sort(list,new CompareByAge()); for(Person p:list){ System.out.println(p.getName()+":"+p.getAge()); } }

    示例2: public class Dog implements Comparable{ private String name; private int age; public Dog(String name,int age){ this.name = name; this.age = age; } //实现Comparable接口的方法 public int compareTo(Object o) {//参数必须是Object Dog d = null; if(o instanceof Dog){ d = (Dog)o; }

    if(this.getAge()>d.getAge()){ return 1; } if(this.getAge()<d.getAge()){ return -1; } return 0; }

    }

    public class DemoDog { public static void main(String[] args) { Dog d1 = new Dog(“c”,24); Dog d2 = new Dog(“b”,8); Dog d3 = new Dog(“a”,34);

    List<Dog> list = new ArrayList<Dog>(); list.add(d1); list.add(d2); list.add(d3); //未排序之前 for(Dog d:list){ System.out.println(d.getName()+":"+d.getAge()); } //按年龄排序之后 System.out.println("按年龄排序之后"); Collections.sort(list); for(Dog d:list){ System.out.println(d.getName()+":"+d.getAge()); } }

    }

    34:Vector和ArrayList Verctor的大多数成员方法都会加上synchronized关键字,也就是说Vector是线程安全的;也正因如此,它的执行效率没ArrayList高;通常建议使用ArrayList

    35:HashTable和HashMap的区别 ① HashTable是线程安全的,HashMap不是 ② HashTable不允许null值(key和value都不可以),HashMap可以 ③ HashTable有个contains()方法,功能和HashMap的containsValue()一样 ④ HashTable使用Enumeration遍历,HashMap使用Iterator

    36:符合什么条件的数据集合可以使用foreach循环 从JDK5开始可以使用foreach代替迭代器,从语法上讲,数组或者实现了Iterable接口的类实例,都可以用foreach循环。

    实例1:(迭代器模式方法) public class Person { private String name; private int age; public Person(String name,int age){ this.name = name; this.age = age; } ………setters and getters… }

    public class Persons implements Iterable{ Listpersonlist = new ArrayList(); //实现Iterable的方法 public Iterator iterator() { PersonIterate pt = new PersonIterate(); pt.setPersonList(personlist); return pt;

    } public void add(Person p){ personlist.add(p); }

    } public class PersonIterate implements Iterator{ Listpersonlist = new ArrayList(); private int index = 0;

    public void setPersonList(List<Person>personlist){ this.personlist = personlist; } public boolean hasNext() { // TODO Auto-generated method stub return personlist.size()>index; } public Person next() { // TODO Auto-generated method stub return personlist.get(index++); } public void remove() { // TODO Auto-generated method stub personlist.remove(index); }

    }

    这样下面的foreach就能成功; Persons persons = new Persons(); persons.add(new Person(“a”,1)); persons.add(new Person(“b”,2)); persons.add(new Person(“c”,3));

    for(Person p:persons){ System.out.println(p.getName()+":"+p.getAge()); }

    实例2:(内部类方法) public class Persons2 implements Iterable{ Listpersonlist = new ArrayList(); public void add(Person p){ personlist.add(p); } public Iterator iterator() {

    // TODO Auto-generated method stub return new Iterator<Person>(){ //用局部内部类实现 private int index=0; public boolean hasNext() { return personlist.size()>index;//可以访问外部类成员 } public Person next() { return personlist.get(index++); } public void remove() { personlist.remove(index); } }; }

    }

    这样也能进行foreach循环了

    说明:Persons也可直接实现Iterator接口,并实现其hasNext(),next()等方法,但是这样的话Persons必须维护一个索引index,其index值是不确定的,如进行循环一次,index变为a,紧接着进行第二次循环遍历会得到空结果; 方法1和方法2每次进行循环迭代都将产生一个新的索引为0;

    37:目录和文件操作 Java提供了java.io.File类对目录和文件进行操作,主要操作方法包括:路径字符串的构造方法、isDirectory、isFile、createNewFile、list(返回文件数组)、getName、delete、getLastModify(返回最近修改时间)、listFile(返回文件名数组)等

    38:随机存取文件RandomAccessFile类 主要方法包括new RandomAccessFile(“路径”,”rw|r|w…”); length()方法获得文件内容长度 seek()定位 read()获取当前位置数据 write()写数据 close()关闭打开的文件 示例:(将文件中所有字母a替换成c) RandomAccessFile raf =new RandomAccessFile(“d:/1.txt”, “rw”); int len = (int) raf.length();//length()返回long类型 for(int i=0;i

    转载请注明原文地址: https://ju.6miu.com/read-1200191.html
    最新回复(0)