Java基础面试题总结(超详细的基础知识点)

1.&和&&的区别?

&:逻辑与(and),运算符两边的表达式均为true时,整个结果才为true。

&&:短路与,如果第一个表达式为false时,第二个表达式就不会计算了。

2.在java中如何跳出当前的多重循环?

在循环语句外前面定义一个标号,然后在里层循环体的代码中使用带有标号的break语句,即可跳出循环。

比如:

ok:

for (int i = 0; i < 10; i++) {

{

for (int j = 0; j < 10; j++) {

break ok;

}

}

}

3.最有效率的方法算出2X8等于几?

使用位运算,效率最高:2<<3,表示2向左移动了3位,就相当于2乘以2的3次方,结果:16。

4.==和equals方法究竟有什么区别?

==:表示两个变量的值是否相等,比较两个基本数据类型的数据或者引用变量,用==。

equals:用于比较两个独立对象的内容是否相同。字符串的比较也用equals。

5. Int和integer的区别?

Int是Java的8中基本数据类型之一,integer是int的封装类。Int类型的默认值为0,integer默认值为null,所以区别在于,integer能区分出null值和0的区别。

八大基本数据类型:数值型(整数类型(byte , int , short , long)浮点类型(float ,double) )  、字符型(char  )、布尔值 (boolean)

引用数据类型:类、接口、数组

6.三个与取整有关的方法:

Math.ceil():表示向上取整;Math.ceil(11.3)=12;Math.ceil(-11.3)=-12。

Math.floor():表示向下取整;Math.floor(11.6)=11;Math.floor(-11.6)=-12。

Math.round():表示四舍五入;Math.round(11.5)=12;Math.round(-11.5)=-11;

Math.round(11.3)=11;Math.round(-11.3)=-11;

7.重载和重写的区别?

重载(Overload)函数名相同,参数不同。可以改变返回值类型,参数的个数和类型。

与访问控制符、返回值类型等无关。

重写(Override):和父类的的方法名称、参数必须完全相同。

子类的返回值类型要等于或者小于父类的返回值类型等。

子类的作用域不能大于父类中方法的作用域,子类抛出的异常类型不能大于父类中抛出的异常类型。

重写用于更改父类方法的行为或者实现接口的方法。而重载用于为一个行为提供多种实现方式。

8.面向对象的特征?

封装:将对象属性和方法的代码封装到一个模块中,也就是一个类中,保证软件内部具有优良的模块性的基础,实现“高内聚,低耦合”。

抽象:找出一些事物的相似和共性之处,然后归为一个类,该类只考虑事物的相似和共性之处。抽象包括行为抽象和状态抽象。

继承:在已经存在的类的基础上进行,将其定义的内容作为自己的内容,并可以加入新的内容或者修改原来的方法适合特殊的需要。

抽象类和接口的区别

1.抽象类要被继承,接口要被实现

2、接口只能做方法声明,抽象类中可以作方法声明,也可以做方法实现

3、抽象类和接口都是用来抽象具体对象的,但是接口的抽象级别最高。

4、接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量

多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,就是多态,简单点说:就是用父类的引用指向子类的对象。目的:提高代码复用性,解决项目中紧耦合问题,提高可扩展性。

多态的机制:靠的是父类的或者接口的引用变量可以指向子类或者具体实现类的实例对象。

public class Test {
    public static void main(String[] args) {
      show(new Cat());  // 以 Cat 对象调用 show 方法
      show(new Dog());  // 以 Dog 对象调用 show 方法
                
      Animal a = new Cat();  // 向上转型  
      a.eat();               // 调用的是 Cat 的 eat
      Cat c = (Cat)a;        // 向下转型  
      c.work();        // 调用的是 Cat 的 work
  }  
            
    public static void show(Animal a)  {
      a.eat();  
        // 类型判断
        if (a instanceof Cat)  {  // 猫做的事情 
            //instanceof属于java关键字之一,instanceof 严格来说是Java中的一个双目运算符,用        来测试一个对象是否为一个类的实例,用法为:boolean result = obj instanceof Class 其中 obj 为一个对象,Class 表示一个类或者一个接口
            Cat c = (Cat)a;  
            c.work();  
        } else if (a instanceof Dog) { // 狗做的事情 
            Dog c = (Dog)a;  
            c.work();  
        }  
    }  
}
 
abstract class Animal {  
    abstract void eat();  
}  
  
class Cat extends Animal {  
    public void eat() {  
        System.out.println("吃鱼");  
    }  
    public void work() {  
        System.out.println("抓老鼠");  
    }  
}  
  
class Dog extends Animal {  
    public void eat() {  
        System.out.println("吃骨头");  
    }  
    public void work() {  
        System.out.println("看家");  
    }  
}

9.String和StringBuffuer、StringBuilder的区别?

String:字符串数值不可变;

StringBuffer:字符串可修改,可以动态构造字符数据。StringBuffer类是可以通过Append()来修改值。线程安全。

 A:StringBuffer的替换功能

* public StringBuffer replace(int start,int end,String str):

* 从start开始到end用str替换

 B:StringBuffer的反转功能

* public StringBuffer reverse():

* 字符串反转

*/

public static void main(String[] args) {
StringBuffer sb1=new StringBuffer("KobeBryant");

//字符串替换
sb1.replace(0, 4, "KG");//前闭后包    >=0 , < 4 

System.out.println(sb1);//KGBryant

sb1.reverse();

System.out.println(sb1);//tnayrBGK

}

StringBuilder:线程不安全。

三者在执行速度方面的比较:StringBuilder >  StringBuffer  >  String   

对于三者使用的总结:

1.如果要操作少量的数据用 = String  

2.单线程操作字符串缓冲区下操作大量数据 = StringBuilder

3.多线程操作字符串缓冲区下操作大量数据 = StringBuffer

10.java中有几种方法实现一个线程?用什么关键字修饰同步方法?stop()和suspend()方法为何不推荐使用? 

继承Thread类 ,New Thread(){}.start():表示调用子类对象的run方法。(优势:编写简单;劣势:单继承的限制----无法继承其它父类,同时不能实现资源共享。)

实现 Runable 接口,实现run方法   (优势:可继承其它类,多线程可共享同一个Thread对象;劣势:编程方式稍微复杂,如需访问当前线程,需调用Thread.currentThread()方法。)

实现 Callable 里面的 call 方法(继承Thread类实现多线程,重写run方法时没有返回值不能抛出异常,使用Callable接口就可以解决这个问题。)

线程池创键多线程

Callable接口和Runnable接口的不同之处:

1.Callable规定的方法是call,而Runnable是run

2.call方法可以抛出异常,但是run方法不行

3.Callable对象执行后可以有返回值,运行Callable任务可以得到一个Future对象,通过Future对象可以了解任务执行情况,可以取消任务的执行,而Runnable不可有返回值

synchronized 关键字修饰同步方法

反对使用stop(),是因为它不安全。它会解除由线程获取的所有锁定,而且如果对象处于一种不连贯状态,那么其他线程能在那种状态下检查和修改它们,结果很难检查出真正的问题所在。

suspend() 方法容易发生死锁。调用 suspend() 的时候,目标线程会停下来,但却仍然持有在这之前获得的锁定。此时,其他任何线程都不能访问锁定的资源,除非被" 挂起"的线程恢复运行。对任何线程来说,如果它们想恢复目标线程,同时又试图使用任何一个锁定的资源,就会造成死锁。所以不应该使用 suspend() ,而应在自己的 Thread 类中置入一个标志,指出线程应该活动还是挂起。若标志指出线程应该挂起,便用  wait() 命其进入等待状态。若标志指出线程应当恢复,则用一个 notify()重新启动线程。

11.sleep()和wait()有什么区别?

sleep是线程被调用时,占着cpu休眠,其他线程不能占用cpu,os认为该线程正在工作,不会让出系统资源,wait是进入等待池等待,让出系统资源,其他线程可以占用cpu。

sleep()和wait()方法的区别可从两个角度阐述:
1.cpu的抢占权;2.锁旗标是否释放
两者都会释放cpu的抢占权;
wait()方法执行完即可释放锁旗标,进入线程的等待队列;
sleep()执行完,不会释放,进入等待队列;

Synchronized加锁是非公平锁

当一个线程想获取锁时,先试图插队,如果占用锁的线程释放了锁,下一个线程还没来得及拿锁,那么当前线程就可以直接获得锁;如果锁正在被其它线程占用,则排队,排队的时候就不能再试图获得锁了,只能等到前面所有线程都执行完才能获得锁。

12. 同步和异步的区别?同步的实现方法?

同步:发送一个请求,等待返回,然后再发送下一个请求。实现:1. Synchronized修饰;2.wait和notify。
异步:发送一个请求,不等待返回,随时可以再发送下一个请求。

同步可以避免出现死锁,读脏数据的发生,一般共享某一资源的时候用,如果每个人都有修改权限,同时修改一个文件,有可能使一个人读取另一个人已经删除的内容,就会出错,同步就会按顺序来修改。

同步和异步最大的区别就在于,一个需要等待,一个不需要等待

比如广播,就是一个异步例子。发起者不关心接收者的状态。不需要等待接收者的返回信息。

电话,就是一个同步例子。发起者需要等待接收者,接通电话后,通信才开始。需要等待接收者的返回信息。

13. 请对比synchronized与java.util.concurrent.locks.Lock的异同

主要相同点:Lock能完成synchronized所实现的所有功能
主要不同点:Lock有比synchronized更精确的线程语义和更好的性能。synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放

14.String  s =new  String (syz);创建了几个String Object?

1.如果String常理池(常量缓冲区)中,已经创建"xyz",则不会继续创建,此时只创建了一个对象new String("xyz");

2.如果String常理池中,没有创建"xyz",则会创建两个对象,一个对象的值是"xyz",一个对象new String("xyz")。

15.作用域public、private、protected 以及不写时的区别?

private修饰的成员变量和函数只能在类本身和内部类中被访问

protected 修饰的成员变量和函数能被类本身、子类及同一个包中的类访问

public修饰的成员变量和函数可以被类、子类、同一个包中的类以及任意其他类访问

默认情况(不写)下,属于一种包访问,即能被类本身以及同一个包中的类访问。

 16.forward和redirect两种跳转方式的区别?

1.从地址栏显示来说

forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器.浏览器根本不知道服务器发送的内容从哪里来的,所以它的地址栏还是原来的地址.

redirect是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址.所以地址栏显示的是新的URL.

2.从数据共享来说

forward:转发页面和转发到的页面可以共享request里面的数据.

redirect:不能共享数据.

3.从运用地方来说

forward:一般用于用户登陆的时候,根据角色转发到相应的模块.

redirect:一般用于用户注销登陆时返回主页面和跳转到其它的网站等.

4.从效率来说

forward:高.

redirect:低.

本质上说, 转发是服务器行为,重定向是客户端行为。其工作流程如下:

转发过程:客户浏览器发送http请求----》web服务器接受此请求--》调用内部的一个方法在容器内部完成请求处理和转发动作----》将目标资源发送给客户;在这里,转发的路径必须是同一个web容器下的url,其不能转向到其他的web路径上去,中间传递的是自己的容器内的request。在客户浏览器路径栏显示的仍然是其第一次访问的路径,也就是说客户是感觉不到服务器做了转发的。转发行为是浏览器只做了一次访问请求。

重定向过程:客户浏览器发送http请求----》web服务器接受后发送302状态码响应及对应新的location给客户浏览器--》客户浏览器发现是302响应,则自动再发送一个新的http请求,请求url是新的location地址----》服务器根据此请求寻找资源并发送给客户。在这里 location可以重定向到任意URL,既然是浏览器重新发出了请求,则就没有什么request传递的概念了。在客户浏览器路径栏显示的是其重定向的路径,客户可以观察到地址的变化的。重定向行为是浏览器做了至少两次的访问请求的。

18.编程单例模式:写一个singleton出来

Singleton分为:饱汉模式(懒汉)、饥汉模式、双重锁模式

//饱汉模式:类加载时完成初始化,创建出实例对象(不管用不用,先创建)。

public class SingleTon {

//实例化对象放到静态代码块中,可提高执行效率,但是可能更占用空间

private final static SingleTon instence=new SingleTon();

private SingleTon(){};//私有的构造函数

//获取方法

public static SingleTon getinstance(){

return instence;

};

}
//饥汉模式:延迟加载,在第一次用的时候才创建出对象,存在线程安全问题。

public class SingleTon {

private  static SingleTon instence=null;

private SingleTon(){};//私有的构造函数

//获取方法

public static synchronized SingleTon getinstance(){

if(instence==null){

//第一次使用的时候创建对象

instence=new SingleTon();

}

return instence;

};

}

19.编程冒泡排序:用java实现冒泡排序?快速排序的方法。

int temp = 0;

int[] sortNum = {12,33,28,86,15,62,9,38};

for (int i = 0; i < sortNum.length-1; i++) {  //第一个for循环控制排序要走多少趟,最多做n-1趟排序  

    for (int j = 0; j < sortNum.length-1-i; j++) { //第2个for循环控制每趟比较多少次  

                if(sortNum[j+1]<sortNum[j]){  //大的 往后面排  

                    temp = sortNum[j];  

                    sortNum[j] = sortNum[j+1];  

                    sortNum[j+1] = temp;  

                }  

    }

}

System.out.println(Arrays.toString(sortNum));

1.对基本数据类型数组的排序

1>数字排序:

int[] intArray = new int[]{1,56,-5,33};

Arrays.sort(intArray);

System.out.println(Arrays.toString(intArray));

2>字符串排序(先大写后小写):

String[] strArray = new String[]{"Z", "a", "D"};

Arrays.sort(strArray);

System.out.println(Arrays.toString(strArray));

20.HashMap和Hashtable的区别?

HashMap实现了Map接口允许空(null)键值(key),由于非线程安全,在只有一个线程访问的情况下,效率高于Hashtable。

Hashtable不能将null作为key或者value。方法是同步的,线程安全。

21.List、Set和Map的区别?

List:是存储单列数据的集合,存储有顺序,允许重复。继承Collection接口。

Set: 是存储单列数据的集合。继承Collection接口。不允许重复。

Map:存储键和值这样的双列数据的集合,存储数据无顺序,键(key)不能重复,值(value)。可以重复。

22.什么时候用assert(断言)? 

调试程序时使用,对一个boolean表达式进行检查。为true,则程序正确,如果为false,系统则给出警告或者退出,该语句强抛出一个AssertionError对象。(可以将断言看作是异常处理的一种高级形式

如果说异常是防御外敌,那么断言就是防内患。(打疫苗)

Java有三种异常结束,断言,异常,错误。

断言是判断输入是否正确

异常处理逻辑错误

错误业务以外的错误,比如硬件错误,内存不足

23.使用java.lang.Math,生成100个0到99之间的随机整数,找出最大和最小,并统计大于50的整数个数?

import java.util.Random;

public class RandomTest {

public static void main(String args[]) {

int max = 0;

int min = 0;

String sum="";

int num=0;

for (int i = 0; i <= 100; i++) {

Random rand = new Random();//备注:Random rand = new Random();

  //int r = rand.nextInt(99);

  //表示产生的随机数为0-99的整数,不包括99。  

int r = rand.nextInt(99);

if (r >= max) {

max = r;

} else if (r < min) {

min = r;

}

String s= ""+r;

if (r > 50) {

sum=sum+s+",";

++num;

}

}

System.out.println("最大数max=" + max + "\n" + "最小数min=" + min);

System.out.println("大于50的个数:"+num);

}

}

 

24.java创建对象的方式有哪些?

1.使用new关键字

2.使用反射机制创建对象:

(1)使用Class类的newInstance方法

(2)java.lang.reflect.Constructor类里也有一个newInstance方法可以创建对象。

3.使用clone方法:先实现Cloneable接口并实现其定义的clone方法

4.使用反序列化

25.java垃圾回收机制

GC是垃圾回收机制,是用来释放内存中的资源的

垃圾回收可以有效的防止内存泄露,有效的使用空闲的内存

26.error和exception有什么区别?

Error(错误)表示系统级的错误和程序不必处理的异常,是java运行环境中的内部错误或者硬件问题。比如:内存资源不足等。对于这种错误,程序基本无能为力,除了退出运行外别无选择,它是由Java虚拟机抛出的。

Exception(违例)表示需要捕捉或者需要程序进行处理的异搜索常,它处理的是因为程序设计的瑕疵而引起的问题或者在外的输入等引起的一般性问题,是程序必须处理的。

Exception又分为运行时异常受检查异常

       运行时异常,表示无法让程序恢复的异常,导致的原因通常是因为执行了错误的操作,建议终止程序,因此,编译器不检查这些异常。

       受检查异常,是表示程序可以处理的异常,也即表示程序可以修复(由程序自己接受异常并且做出处理), 所以称之为受检查异常。

27.Int如何去重复?

1.For循环

2.Set集合

28.JDBC使用步骤过程?

1.加载JDBC驱动

2.提供JDBC连接的URL

3.创键数据库的连接(Connection)

4.创键一个Statement(执行者对象)

5.处理结果集

6.释放资源

public class StudentDaoImpl implements StudentDao {

    /*
        查询所有学生信息
     */
    @Override
    public ArrayList<Student> findAll() {
        Connection con = null;
        Statement stat = null;
        ResultSet rs = null;
        ArrayList<Student> list = new ArrayList<>();
        try {
            //1.获取连接
            con = JDBCUtils.getConnection();

            //2.获取执行者对象
            stat = con.createStatement();

            //3.执行sql语句,并接收结果
            String sql = "SELECT * FROM student";
            rs = stat.executeQuery(sql);

            //4.处理结果,将每条记录封装成一个Student对象。将多个Student对象保存到集合中
            while(rs.next()) {
                Integer sid = rs.getInt("sid");
                String name = rs.getString("name");
                Integer age = rs.getInt("age");
                Date birthday = rs.getDate("birthday");

                Student stu = new Student(sid,name,age,birthday);

                list.add(stu);
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //5.释放资源
            JDBCUtils.close(con,stat,rs);
        }

        return list;
    }

    /*
        条件查询,根据id查询学生信息
     */
    @Override
    public Student findById(Integer id) {
        Connection con = null;
        Statement stat = null;
        ResultSet rs = null;
        Student stu = new Student();
        try {
            //1.获取连接
            con = JDBCUtils.getConnection();

            //2.获取执行者对象
            stat = con.createStatement();

            //3.执行sql语句,并接收结果
            String sql = "SELECT * FROM student WHERE sid='"+id+"'";
            rs = stat.executeQuery(sql);

            //4.处理结果,将记录封装成一个Student对象。
            if(rs.next()) {
                Integer sid = rs.getInt("sid");
                String name = rs.getString("name");
                Integer age = rs.getInt("age");
                Date birthday = rs.getDate("birthday");

                stu.setSid(sid);
                stu.setName(name);
                stu.setAge(age);
                stu.setBirthday(birthday);
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //5.释放资源
            JDBCUtils.close(con,stat,rs);
        }

        return stu;
    }

    /*
        新增学生信息
     */
    @Override
    public int insert(Student stu) {
        Connection con = null;
        Statement stat = null;
        int result = 0;
        try{
            //1.获取连接
            con = JDBCUtils.getConnection();

            //2.获取执行者对象
            stat = con.createStatement();

            //3.执行sql语句,并接收结果
            Date date = stu.getBirthday();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            String birthday = sdf.format(date);
            String sql = "INSERT INTO student VALUES (null,'"+stu.getName()+"','"+stu.getAge()+"','"+birthday+"')";
            result = stat.executeUpdate(sql);

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //4.释放资源
            JDBCUtils.close(con,stat);
        }

        return result;
    }

    /*
        修改学生信息
     */
    @Override
    public int update(Student stu) {
        Connection con = null;
        Statement stat = null;
        int result = 0;
        try{
            //1.获取连接
            con = JDBCUtils.getConnection();

            //2.获取执行者对象
            stat = con.createStatement();

            //3.执行sql语句,并接收结果
            Date date = stu.getBirthday();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            String birthday = sdf.format(date);
            String sql = "UPDATE student SET sid='"+stu.getSid()+"',name='"+stu.getName()+"',age='"+stu.getAge()+"',birthday='"+birthday+"' WHERE sid='"+stu.getSid()+"'";
            result = stat.executeUpdate(sql);

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //4.释放资源
            JDBCUtils.close(con,stat);
        }

        return result;
    }

    /*
        删除学生信息
     */
    @Override
    public int delete(Integer id) {
        Connection con = null;
        Statement stat = null;
        int result = 0;
        try{
            //1.获取连接
            con = JDBCUtils.getConnection();

            //2.获取执行者对象
            stat = con.createStatement();

            //3.执行sql语句,并接收结果
            String sql = "DELETE FROM student WHERE sid='"+id+"'";
            result = stat.executeUpdate(sql);

        } catch (SQLException e) {
            e.printStackTrace();
        }  finally {
            //4.释放资源
            JDBCUtils.close(con,stat);
        }

        return result;
    }
}

SQL注入攻击

sql注入攻击的原理

  • 按照正常道理来说,我们在密码处输入的所有内容,都应该认为是密码的组成

  • 但是现在Statement对象在执行sql语句时,将一部分内容当做查询条件来执行了

预编译sql语句的执行者对象。在执行sql语句之前,将sql语句进行提前编译。明确sql语句的格式后,就不会改变了。剩余的内容都会认为是参数!参数使用?作为占位符

  • 为参数赋值的方法:setXxx(参数1,参数2);

    • 参数1:?的位置编号(编号从1开始)

    • 参数2:?的实际参数

  • 执行sql语句的方法

  • 执行insert、update、delete语句:int executeUpdate();

  • 执行select语句:ResultSet executeQuery();

(PreparedStatement 的使用

1.获取连接

2.创建操作sql对象

3.设置参数

4.执行sql语句,获取结果集

5.获取结果集

6.返回

/*
	 使用PreparedStatement的登录方法,解决注入攻击
*/
@Override
public User findByLoginNameAndPassword(String loginName, String password) {
    //定义必要信息
    Connection conn = null;
    PreparedStatement pstm = null;
    ResultSet rs = null;
    User user = null;
    try {
        //1.获取连接
        conn = JDBCUtils.getConnection();
        //2.创建操作SQL对象
        String sql = "SELECT * FROM user WHERE loginname=? AND password=?";
        pstm = conn.prepareStatement(sql);
        //3.设置参数
        pstm.setString(1,loginName);
        pstm.setString(2,password);
        System.out.println(sql);
        //4.执行sql语句,获取结果集
        rs = pstm.executeQuery();
        //5.获取结果集
        if (rs.next()) {
            //6.封装
            user = new User();
            user.setUid(rs.getString("uid"));
            user.setUcode(rs.getString("ucode"));
            user.setUsername(rs.getString("username"));
            user.setPassword(rs.getString("password"));
            user.setGender(rs.getString("gender"));
            user.setDutydate(rs.getDate("dutydate"));
            user.setBirthday(rs.getDate("birthday"));
            user.setLoginname(rs.getString("loginname"));
        }
        //7.返回
        return user;
    }catch (Exception e){
        throw new RuntimeException(e);
    }finally {
        JDBCUtils.close(conn,pstm,rs);
    }
}

29.运行时异常与一般异常有何异同?

Java提供了两类主要的异常:运行时异常runtime exception一般异常checked exception对于后者这种一般异常,JAVA要求程序员对其进行catch处理。所以,面对这种异常不管我们是否愿意,只能自己去写一大堆catch块去处理可能的异常

运行时异常我们可以不处理这样的异常由虚拟机接管。出现运行时异常后,系统会把异常一直往上层抛,一直遇到处理代码。如果不对运行时异常进行处理,那么出现运行时异常之后,要么是线程中止,要么是主程序终止

30.抽象类和接口区别?

抽象类:用abstract修饰,抽象类不能创建实例对象。抽象方法必须在子类中实现,不能有抽象构造方法或者抽象静态方法。

接口:抽象类的一种特例,接口中的方法必须是抽象的。

两者的区别:

  1. 抽象类可以有构造方法,接口没有构造方法
  2. 抽象类可以有普通成员变量,接口没有普通成员变量。
  3. 抽象类可以有非抽象的普通方法,接口中的方法必须是抽象的。
  4. 抽象类中的抽象方法访问类型可以是public,protected,接口中抽闲方法必须是public类型的。
  5. 抽象类可以包含静态方法,接口中不能包含静态方法。
  6. 一个类可以实现多个接口,但是只能继承一个抽象类。

7.接口中基本数据类型的数据成员,都默认为static和final,抽象类则不是。

31.如何获取map集合中的数据?

// 方法一: for each  +  map.keySet();   

Set<Integer> set = map.keySet();  

for (Integer key : set) {  

    System.out.println("key:" + key + ", value:" + map.get(key));  

}

// 方法二:while循环(Iterator  +  map.keySet();)  

Set<Integer> set = map.keySet();  

Iterator<Integer> it = set.iterator();  

while(it.hasNext()){  

    Integer key = it.next();  

    System.out.println("key:" + key + ", value:" + map.get(key));  

}

// 方法三:while循环(Iterator +Map.Entry<Key, Value>)  

Iterator<Map.Entry<Integer, String>> it = map.entrySet().iterator();  

while (it.hasNext()) {  

    Map.Entry<Integer, String> entry = it.next();  

    System.out.println("key:"+entry.getKey() + ", value:"+entry.getValue());  

}

// 方法四:for循环(Iterator + Map.Entry<Key, Value>)  

for(Iterator<Map.Entry<Integer, String>> it = map.entrySet().iterator(); it.hasNext();){  

    Map.Entry<Integer, String> entry = it.next();  

    System.out.println("key:" + entry.getKey() + ", value:" +entry.getValue());  

}

// 方法五:for each  +  Map.Entry<Key, Value>  

for(Map.Entry<Integer, String> entry : map.entrySet()){  

    System.out.println("key:" + entry.getKey() + ", value:" +entry.getValue());  

}

32.hashCode与equals的区别与联系?

equals方法主要用于判断对象的内存地址引用是不是同一个地址(是不是同一个对象)。

1、equals方法用于比较对象的内容是否相等(覆盖以后)

2、hashcode方法只有在集合中用到

3、当覆盖了equals方法时,比较对象是否相等将通过覆盖后的equals方法进行比较(判断对象的内容是否相等)。

4、将对象放入到集合中时,首先判断要放入对象的hashcode值与集合中的任意一个元素的hashcode值是否相等,如果不相等直接将该对象放入集合中。如果hashcode值相等,然后再通过equals方法判断要放入对象与集合中的任意一个对象是否相等,如果equals判断不相等,直接将该元素放入到集合中,否则不放入。

33.Java中什么是竞态条件?

两个线程竞争同一资源时如果对资源的访问顺序敏感,就称存在竞态条件导致竞态条件发生的代码区称作临界区。在临界区中使用适当的同步就可以避免竞态条件。 界区实现方法有两种,一种是用synchronized,一种是用Lock显式锁实现。

34.线程死锁及解决办法

死锁是指两个或两个以上的进程(线程)在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。

1)、让所有的线程按照同样的顺序获得一组锁。

2)、将多个锁组成一组并放到同一个锁下。

3)、将那些不会阻塞的可获得资源用变量标志出来。

形成死锁的四个必要条件是什么?

1、互斥:某种资源一次只允许一个进程访问,即该资源一旦分配给某个进程,其他进程就不能再访问,直到该进程访问结束。

2、占有且等待:一个进程本身占有资源(一种或多种),同时还有资源未得到满足,正在等待其他进程释放该资源。

3、不可抢占:别人已经占有了某项资源,你不能因为自己也需要该资源,就去把别人的资源抢过来。

4、循环等待:存在一个进程链,使得每个进程都占有下一个进程所需的至少一种资源。

35.ArrayList和LinkList的区别

1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。

2.对于查询修改,ArrayList绝对优于 LinkList ,因为LinkedList要移动指针。

3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据,而查询和修改ArrayList占优势

36.Socket和HTTP区别?

socket则是对TCP/IP协议的封装和应用(程序员层面上), Socket本身并不是协议,而是一个调用接口(API)。也可以说,TPC/IP协议是传输层协议,主要解决数据如何在网络中传输,而HTTP是应用层协议,主要解决如何包装数据。

37.BS与CS的联系与区别?

C/S 与 B/S 区别:

(bs 面向庞大、不同群体、不同平台的客户;cs 面向比较单一的客户)

1.硬件环境不同:

  C/S 一般建立在专用的网络上, 小范围里的网络环境, 局域网之间再通过专门服务器提供连接和数据交换服务.

  B/S 建立在广域网之上的, 不必是专门的网络硬件环境,例与电话上网, 租用设备. 信息自己管理. 有比C/S更强的适应范围, 一般只要有操作系统和浏览器就行

2.对安全要求不同

  C/S 一般面向相对固定的用户群, 对信息安全的控制能力很强. 一般高度机密的信息系统采用C/S 结构适宜. 可以通过B/S发布部分可公开信息.

  B/S 建立在广域网之上, 对安全的控制能力相对弱, 可能面向不可知的用户。

3.对程序架构不同

  C/S 程序可以更加注重流程, 可以对权限多层次校验, 对系统运行速度可以较少考虑.

  B/S 对安全以及访问速度的多重的考虑, 建立在需要更加优化的基础之上. 比C/S有更高的要求 B/S结构的程序架构是发展的趋势, 从MS的.Net系列的BizTalk 2000 Exchange 2000等, 全面支持网络的构件搭建的系统. SUN 和IBM推的JavaBean 构件技术等,使 B/S更加成熟.

4.软件重用不同

  C/S 程序可以不可避免的整体性考虑, 构件的重用性不如在B/S要求下的构件的重用性好.

  B/S 对的多重结构,要求构件相对独立的功能. 能够相对较好的重用.就入买来的餐桌可以再利用,而不是做在墙上的石头桌子

5.系统维护不同

  C/S 程序由于整体性, 必须整体考察, 处理出现的问题以及系统升级. 升级难. 可能是再做一个全新的系统

  B/S 构件组成,方面构件个别的更换,实现系统的无缝升级. 系统维护开销减到最小.用户从网上自己下载安装就可以实现升级.

6.处理问题不同

  C/S 程序可以处理用户面固定, 并且在相同区域, 安全要求高需求, 与操作系统相关. 应该都是相同的系统

  B/S 建立在广域网上, 面向不同的用户群, 分散地域, 这是C/S无法作到的. 与操作系统平台关系最小.

7.用户接口不同

  C/S 多是建立的Window平台上,表现方法有限,对程序员普遍要求较高

  B/S 建立在浏览器上, 有更加丰富和生动的表现方式与用户交流. 并且大部分难度减低,减低开发成本.

8.信息流不同

  C/S 程序一般是典型的中央集权的机械式处理, 交互性相对低

  B/S 信息流向可变化, B-B B-C B-G等信息、流向的变化, 更像交易中心。

38.多线程中thread的start()和run()的区别?

 1) start:

 用start方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码。通过调用Thread类的start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片,就开始执行run()方法,这里方法 run()称为线程体,它包含了要执行的这个线程的内容,Run方法运行结束,此线程随即终止。

 2) run:

  run()方法只是类的一个普通方法而已,如果直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到写线程的目的。总结:调用start方法方可启动线程,而run方法只是thread的一个普通方法调用,还是在主线程里执行。这两个方法应该都比较熟悉,把需要并行处理的代码放在run()方法中,start()方法启动线程将自动调用 run()方法,这是由jvm的内存机制规定的。并且run()方法必须是public访问权限,返回值类型为void。

39.final关键字的用法

一、final修饰类:

被final修饰的类,是不可以被继承的,这样做的目的可以保证该类不被修改,Java的一些核心的API都是final类,例如String、Integer、Math等。

二、final修饰方法

子类不可以重写父类中被final修饰的方法

三、final修饰实例变量(类的属性,定义在类内,但是在类内的方法之外)

final修饰实例变量时必须初始化,且不可再修改。//

四、final修饰局部变量(方法体内的变量)

final修饰局部变量时只能初始化(赋值)一次,但也可以不初始化。

五、final修饰方法参数

final修饰方法参数时,是在调用方法传递参数时候初始化的。

40.怎么遍历一个ArrayList集合

1.迭代器

Collection迭代器中删除的方法

循环遍历删除集合中的元素方式

  • 方式1:采用Collection的remove()方法删除元素,相邻重复元素删除要注意索引问题。

    • 每次删除后索引会重新排序

  • 方式2:建议,通过迭代器对象删除集合中的元素

    • void remove(): 删除迭代器对象当前指向的元素

public class IteratorDemo2 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("b");
        list.add("c");
        list.add("d");

        Iterator<String> it = list.iterator();
        while(it.hasNext()){
            String s = it.next();
            if("b".equals(s)){
                //指向谁,那么此时就删除谁.
                it.remove();
            }
        }
        System.out.println(list);
    }
}

 2.增强for循环

介绍

  • 它是JDK5之后出现的,其内部原理是一个Iterator迭代器

  • 实现Iterable接口的类才可以使用迭代器和增强for

  • 简化数组和Collection集合的遍历

格式

for(集合/数组中元素的数据类型 变量名 :  集合/数组名) {
    // 已经将当前遍历到的元素封装到变量中了,直接使用变量即可

}

代码示例:

public class MyCollectonDemo1 {
    public static void main(String[] args) {
        ArrayList<String> list =  new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        list.add("e");
        list.add("f");

        //1,数据类型一定是集合或者数组中元素的类型
        //2,str仅仅是一个变量名而已,在循环的过程中,依次表示集合或者数组中的每一个元素
        //3,list就是要遍历的集合或者数组
        for(String str : list){
            System.out.println(str);
        }
    }
}

  • 5
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值