面试问题收录

来源:互联网 发布:阿里云cdn添加域名 编辑:程序博客网 时间:2024/06/17 11:23

1,java基础,数据类型

class AutoUnboxingTest {      public static void main(String[] args) {          Integer a = new Integer(3);          Integer b = 3;                  // 将3自动装箱成Integer类型;在java编译的时候, 被翻译成integer b = integer.ValueOf(3)        int c = 3;          System.out.println(a == b);     // **false** 两个引用没有引用同一对象          System.out.println(a == c);     // **true** a自动拆箱成int类型再和c比较      }  }  

integer和int比会自动拆箱,所以a和c,b和c都为true;interger和new integer比不会相等,因为不会经历拆箱过程。

2、CSS中有几种定位,分别是什么,它们的区别是什么?
①relative —- 相对位置,可将其移至相对与其正常位置的地方,其原位置在文本流中仍保持
②absolute —- 绝对位置,可将其移至相对与其正常位置的地方,其原位置在文本流中将被其他元素占据
③fixed —- 固定位置,可将其移至相对于其正常位置的地方,该元素脱离文本流
④static —- 静态位置,默认位置,不可设置偏移量
3、接口是一种只含抽象方法或”常量“的一种特殊抽象类
这里要注意抽象方法和抽象类之间的关系:包含抽象方法的类称为抽象类,但抽象类不一定含有抽象方法(用abstract修饰的类为抽象类,即只声明为抽象类,没有具体的实现)
在Java中,定义一个接口的形式如下:

public  interface interfacename{}```

接口中可以含有变量和方法。但是要注意,接口中的变量会被隐式地指定为public static final变量(并且只能是public static final变量,用private修饰会报编译错误),而方法会被隐式地指定为pubic abstract方法且只能是public abstract方法(用其他关键字如private、protected、static、final等修饰会报编译错误),并且接口中的所有方法不能有具体的实现,也就是说,接口中的方法必须都是抽象的方法。从这里可以隐约看出接口和抽象类的区别,接口是一种极度抽象的类型,它比抽象类更加的“抽象”,并且一般情况下不在接口中定义变量。
要让一个类遵循某组特定的接口需要使用implements关键字,具体格式如下:

class ClassName implements Interface1Interface2,[....]{}

可以看出,允许一个类继承多个接口。如果一个非抽象类遵循了某个接口,就必须实现该接口中的所有方法。对于遵循某个接口的抽象类,可以不实现该接口中的抽象方法。
4、*thread类提供了一系统基本线程控制方法,如果我们需要让与当前线程具有相同优先级也有运行的机会则可以调用“yield()”*方法
5、*Java提供的类库支持”tcp/ip“* 协议,应用程序可通过URL,在访问网络任何地方的对象时,如同访问本地的文件一样简单。
6、简述String和StringBuffer的区别
①内存操作方式不同:
StringBuffer会开辟一块字符串缓冲区来修饰字符串,而String每次修改都会重新申请内存(String类代表不可变字符串。在值创建之后就不能被改变。而String Buffer是可变的字符序列,初始容量为16字节,通过某些方法可改变其内容和长度)
②效率性能不同:
StringBuffer>String
③方法不同
比如追加字符串,String用的是“+”,String Buffer用append方法。
7、this的作用有哪些
①引用成员变量
②调用本类构造方法
③返回本类对象的值
8、简述sleep()和wait()的功能及两者的区别
功能:sleep()和wait()有一个共同的作用,停止当前线程任务运行。
两者区别:①两个方法来自不同的类,sleep()来自Thread类,wait()来自Object类
②sleep()没有释放锁,而wait()释放了锁,使得其他线程可以使用同步控制块和方法
③sleep()的使用范围是仁和地方,wait()的notify和notifyall方法只能在同步控制块和同步方法里面中使用
④sleep()需要捕获异常,而wait()的notify和notifyall不需要捕获异常
9、Hibernate的三种查询数据的方式
HQL查询、QBC查询、原生sql查询。
HQL(Hibernate Query Language)提供了丰富灵活的查询方式,使用HQL进行查询也是Hibernate中的Query对象,该对象专门执行HQL方式的操作。
QBC(Query By Criteria)查询,Criteria对象提供了一种面向对象的方式查询数据库。Criteria对象需要使用Session对象来获得。一个Criteria对象表示对一个持久化的查询。
10、基于Struts开发的应用由控制器组件模型组件视图组件三类组件构成
11、hibernate中”单向多对一关联”和“单向一对多关联“标签配置
12、Java编写一个方法获取网页的数据,参数为网页的地址,返回网页源代码

import Java.io.BufferedReader;import java.io.InputStreamReader;import java.net.HttpURLConnection;import java.net.URL;public class HtmlParser{    String urlString;    public static void main(String[] args)throws Exception{    }    public HtmlParser(String urlString){    this.urlString = urlString;    }//生成一个URL对象    URL url = new URL(urlString);    //打开URL    HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();    //得到输入流,即获得网页的内容    BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));    String line;    //读取输入流的数据,并显示    while((line = reader.readLine())!=null){    System.out.println(line);}    }    }

13、编写一个死锁的程序
代码如下:

public class LockDead{    public static void main(String[] args) {          Object lockA = new Object();          Object lockB = new Object();          new Thread(new Runnable() {              @Override              public void run() {                  String name = Thread.currentThread().getName();                  synchronized (lockA) {                      System.out.println(name + " got lockA,  want LockB");                      try {                          Thread.sleep(100);                      } catch (InterruptedException e) {                          e.printStackTrace();                      }                      synchronized (lockB) {                          System.out.println(name + " got lockB");                          System.out.println(name + ": say Hello!");                      }                  }              }          }, "线程-A").start();          new Thread(new Runnable() {              @Override              public void run() {                  String name = Thread.currentThread().getName();                  synchronized (lockB) {                      System.out.println(name + " got lockB, want LockA");                      try {                          Thread.sleep(100);                      } catch (InterruptedException e) {                          e.printStackTrace();                      }                      synchronized (lockA) {                          System.out.println(name + " got lockA");                          System.out.println(name + ": say Hello!");                      }                  }              }          }, "线程-B").start();      }  }  

14、String、Stringbuffer和Stringbuilder的区别
①String对象长度不可变,Stringbuffer和StringBuilder对象长度可变
String中的字符数据有final修饰(主要是为了“效率” 和 “安全性” 的缘故。若 String允许被继承, 由于它的被使用率很高, 可能会降低程序的性能,所以String被定义成final),为字符串常量,因此String对象是不可变的。

private final char value[];

Stringbuffer和Stringbuilder为字符串变量,对象是可变的。
如下面的代码;

String str = 1234;str = str + 5;System.out.println(str);//输出->12345

从结果来看String对象是可变的,但这只是表面现象,jvm对其的解释是:执行第一行代码的时候在内存区域创建一个1234赋给str,执行第二段代码的时候又新创建了一个12345,即字符串1234+5->12345,重新赋给str,可以看出,原先的1234变量是没有变的。
值得注意的是,jvm中String的“+”运算是自动转化的,编译器会将字符串相加编译成使用StringBuilder拼接相加的字符串。
②执行速度:Stringbuilder>Stringbuffer>String
当我们要对字符串进行 操作时,对于Stringbuffer和StringBuilder来说就是直接对一个对象进行操作,而对于String,每次需要创建新的对象。另外,Stringbuffer对方法或者调用的方法加了同步锁,速度方面稍处劣势。
③线程安全:String,Stringbuffer线程安全,Stringbuilder线程不安全
String中的对象是不可变的,也就可以理解为常量,显然线程安全
Stringbuffer对方法加了同步锁线程安全
Stringbuilder没有加锁,非线程安全。
总结:操作少量数据时->String
单线程的字符串缓冲区下操作大量数据时->Stringbuilder
多线程的字符串缓冲区下操作大量数据时->Stringgbuffer
不考虑线程安全时,首选Stringbuilder。
15、如果不提供jdk工具,自己实现一个map
参考
Entry.java

package edu.sjtu.erplab.hash;public class Entry<K,V>{    final K key;    V value;    Entry<K,V> next;//下一个结点    //构造函数    public Entry(K k, V v, Entry<K,V> n) {        key = k;        value = v;        next = n;    }    public final K getKey() {        return key;    }    public final V getValue() {        return value;    }    public final V setValue(V newValue) {    V oldValue = value;        value = newValue;        return oldValue;    }    public final boolean equals(Object o) {        if (!(o instanceof Entry))            return false;        Entry e = (Entry)o;        Object k1 = getKey();        Object k2 = e.getKey();        if (k1 == k2 || (k1 != null && k1.equals(k2))) {            Object v1 = getValue();            Object v2 = e.getValue();            if (v1 == v2 || (v1 != null && v1.equals(v2)))                return true;        }        return false;    }    public final int hashCode() {        return (key==null   ? 0 : key.hashCode()) ^ (value==null ? 0 : value.hashCode());    }    public final String toString() {        return getKey() + "=" + getValue();    }}

MyHashMap.java

package edu.sjtu.erplab.hash;//保证key与value不为空public class MyHashMap<K, V> {    private Entry[] table;//Entry数组表    static final int DEFAULT_INITIAL_CAPACITY = 16;//默认数组长度    private int size;    // 构造函数    public MyHashMap() {        table = new Entry[DEFAULT_INITIAL_CAPACITY];        size = DEFAULT_INITIAL_CAPACITY;    }    //获取数组长度    public int getSize() {        return size;    }    // 求index    static int indexFor(int h, int length) {        return h % (length - 1);    }    //获取元素    public V get(Object key) {        if (key == null)            return null;        int hash = key.hashCode();// key的哈希值        int index = indexFor(hash, table.length);// 求key在数组中的下标        for (Entry<K, V> e = table[index]; e != null; e = e.next) {            Object k = e.key;            if (e.key.hashCode() == hash && (k == key || key.equals(k)))                return e.value;        }        return null;    }    // 添加元素    public V put(K key, V value) {        if (key == null)            return null;        int hash = key.hashCode();        int index = indexFor(hash, table.length);        // 如果添加的key已经存在,那么只需要修改value值即可        for (Entry<K, V> e = table[index]; e != null; e = e.next) {            Object k = e.key;            if (e.key.hashCode() == hash && (k == key || key.equals(k))) {                V oldValue = e.value;                e.value = value;                return oldValue;// 原来的value值            }        }        // 如果key值不存在,那么需要添加        Entry<K, V> e = table[index];// 获取当前数组中的e        table[index] = new Entry<K, V>(key, value, e);// 新建一个Entry,并将其指向原先的e        return null;    }}

MyHashMap.java

package edu.sjtu.erplab.hash;public class MyHashMapTest {    public static void main(String[] args) {        MyHashMap<Integer, Integer> map = new MyHashMap<Integer, Integer>();        map.put(1, 90);        map.put(2, 95);        map.put(17, 85);        System.out.println(map.get(1));        System.out.println(map.get(2));        System.out.println(map.get(17));        System.out.println(map.get(null));    }}

16、Hashtable和Hashmap的区别
Hashtable底层实现是红黑树,是线程安全的,hashmap底层实现是hash表,即数组加链表的形式,非线程安全的。一般使用hashmap,他的效率一般比hashtable高。
17、Java创建线程之后,直接调用start()方法和run()的区别
start与run方法的主要区别在于当程序调用start方法一个新线程将会被创建,并且在run方法中的代码将会在新线程上运行,然而在你直接调用run方法的时候,程序并不会创建新线程,run方法内部的代码将在当前线程上运行。大多数情况下调用run方法是一个bug或者变成失误。因为调用者的初衷是调用start方法去开启一个新的线程,这个错误可以被很多静态代码覆盖工具检测出来,比如与fingbugs. 如果你想要运行需要消耗大量时间的任务,你最好使用start方法,否则在你调用run方法的时候,你的主线程将会被卡住。另外一个区别在于,一但一个线程被启动,你不能重复调用该thread对象的start方法,调用已经启动线程的start方法将会报IllegalStateException异常, 而你却可以重复调用run方法。
18、设计一个单例模式
来自内容

public class BadSynchronizedSingleton {    //一个静态的实例    private static BadSynchronizedSingleton synchronizedSingleton;    //私有化构造函数    private BadSynchronizedSingleton(){}    //给出一个公共的静态方法返回一个单一实例    public synchronized static BadSynchronizedSingleton getInstance(){        if (synchronizedSingleton == null) {            synchronizedSingleton = new BadSynchronizedSingleton();        }        return synchronizedSingleton;    }}

19、super、this关键字
super表示使用它的类的父类。
作用:
①调用父类的构造方法
②调用父类的方法
③访问父类的数据域(可以这样用但没必要)
注意:super语句必须是子类的构造方法的第一条语句。
不能在子类中使用父类构造方法名来调用 父类的构造方法。父类的构造方法不能被子类继承。调用父类的构造方法的唯一途径是使用super关键字,如果子类中没显示调用,则编译器自动将super();作为子类构造方法的第一条语句。这会形成一个构造方法链。
静态方法中不能适应super关键字。
如果是使用继承的方法,没必要使用super来调用,可直接调用。但如果子类覆盖或重写了父类的方法,则只有使用super才能在子类中调用父类中的被重写的方法。
this关键字表示当前对象。
作用:
①调用当前类的构造方法,并且必须是方法的第一条语句。如this();调用默认构造方法,this(参数);调用带参数 的构造方法
②限定当前对象的数据域变量。一般用于方法内的局部变量与对象的数据域变量同名的情况。如this.num = num。this.num表示当前对象的数据域变量num,而num表示方法中的局部变量。