java面试笔记第二次记录

1.java内存结构

(1).虚拟机栈 :即栈。每个线程执行方法的时候都会创建一个栈帧,包含操作数栈和局部变量区,用于存放本次方法调用过程中的临时变量、参数和中间结果

(2).堆:所有通过new创建的对象的内存都在堆中分配。堆分为新生代、老年代。

 新生代:分为1个Eden和2个Survivor(from和to)。对象开始创建在Eden中,Eden执行一次gc后的对象会被移动到  幸存者区(from),此后Eden执行gc的后的对象依然会被移动到同一个幸存者区,当一个幸存者区饱和还存活的对

 象会被移动到到另外一个幸存者区(to),之后清空已经饱和的幸存者区,重复以上几个步骤依然存活的对象会被

 移动到老年代。

(3).本地方法栈:和虚拟机栈功能相似,但管理的不是JAVA方法,是本地方法

(4).方法区:存放了要加载的类信息、静态变量、final类型的常量、属性和方法信息,是JVM的永久代。

(5).程序计数器:用于取下一条执行的指令

3.java虚拟机算法

  •        标记——清除算法:
       最基础的收集算法,分为“标记”和“清除”两个阶段,首先标记所有需要回收的对象,然后统一回收所有标记对象
       后续算法都是基于此思想并改进       
       主要缺点:一、效率低,二、空间浪费,标记清除之后会产生大量不连续的内存碎片,当需要分配较大对象时,不得不提前触发另一次垃圾回收。
  •        复制算法:
       为解决效率问题,提出复制的算法
       将内存一分为相等的两块,每次只使用一块。当这一块内存用光,就将还存活的对象复制到另外一块,然后再把已经使用过的空间一次清理掉。
       优点:每次只针对其中一块进行内存回收,内存分配也不用考虑内存碎片等复杂情况,只要一点堆顶指针,按顺序分配内存即可。实现简单,运行高效。
       缺点:内存缩小为原来的一半。
       用于回收新生代,因为新生代对象对象98%是朝生夕死的,所以并不需要按1:1划分空间,而是将内存分为一块较大的Eden和两块较小的Survivor空间,每次使用Eden和其中的一块Survivor空间。如果另外一块Survivor没有足够的空间存放上一次新生代存活下来的对象,这些对象将会分配到老年代。
  • 标记——整理算法:
       复制算法在对象存活率较高时要多次执行复制操作,效率低,而且如果不想浪费50%空间,就要有额外空间进行担保,以应对极端情况。所有老年代不能使用复制算法。
       标记与之前一样,整理指的是让所有存活对象都移向一端,然后直接清理掉端边界以外的内存
  • 分代收集算法
       将内存按照对象存活周期的不同,划分为几块。
       新生代和老年代:新生代由于存活对象少,使用复制算法,老年代由于对象存活率高,无额外空间担保,使用“标记——清除”或“标记——整理”算法。

4.面向对象的特征有哪些方面

(1)封装

(2)继承

(3)多态

5.访问修饰符public,private,protected,以及不写(默认)时的区别? 

修饰符 当前类 同 包 子 类 其他包
public
protected ×
default × ×
private × × ×


6.、String 是最基本的数据类型吗? 

答:不是。Java中的基本数据类型只有8个:byte、short、int、long、float、double、char、boolean;

对应的包装类Byte、Short、Integer、Long、Float、Double、Character、Boolean

7.float f=3.4;是否正确?

答:不正确。3.4是双精度数,将双精度型(double)赋值给浮点型(float)属于下转型(down-casting,也称为窄

化)会造成精度损失,因此需要强制类型转换float f =(float)3.4; 或者写成float f =3.4F;。

8.short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗? 

答:对于short s1 = 1; s1 = s1 + 1;由于1是int类型,因此s1+1运算结果也是int 型,需要强制转换类型才能赋值给

short型。而short s1 = 1; s1 += 1;可以正确编译,因为s1+= 1;相当于s1 = (short)(s1 + 1);其中有隐含的强制类型转

换。

9.Java有没有goto? 

答:goto 是Java中的保留字,在目前版本的Java中没有使用。

10.&和&&的区别? 
答:&运算符有两种用法:(1)按位与;(2)逻辑与。&&运算符是短路与运算。逻辑与跟短路与的差别是非常巨大的,

虽然二者都要求运算符左右两端的布尔值都是true整个表达式的值才是true。&&之所以称为短路运算是因为,如果&&

左边的表达式的值是false,右边的表达式会被直接短路掉,不会进行运算。很多时候我们可能都需要用&&而不是&,

例如在验证用户登录时判定用户名不是null而且不是空字符串,应当写为:username != null

 &&!username.equals(""),二者的顺序不能交换,更不能用&运算符,因为第一个条件如果不成立,根本不能进行字

符串的equals比较,否则会产生NullPointerException异常。注意:逻辑或运算符(|)和短路或运算符(||)的差别也

是如此。

11.Math.round(11.5) 等于多少?Math.round(-11.5)等于多少? 
答:Math.round(11.5)的返回值是12,Math.round(-11.5)的返回值是-11。四舍五入的原理是在参数上加0.5然后进行

下取整。

12.switch 是否能作用在byte 上,是否能作用在long 上,是否能作用在String上? 
答:在Java 5以前,switch(expr)中,expr只能是byte、short、char、int。从Java 5开始,Java中引入了枚举类型,

expr也可以是enum类型,从Java 7开始,expr还可以是字符串(String),但是长整型(long)在目前所有的版本中

都是不可以的。

13.用最有效率的方法计算2乘以8? 

答: 2 << 3(左移3位相当于乘以2的3次方,右移3位相当于除以2的3次方)。

14.数组有没有length()方法?String有没有length()方法? 
答:数组没有length()方法,有length 的属性。String 有length()方法。

15.在Java中,如何跳出当前的多重嵌套循环? 
答:在最外层循环前加一个标记如A,然后用break A;可以跳出多重循环。

例子:

 public static void main(String args[]){  
        OK:                    //设置一个标记 使用带此标记的break语句跳出多重循环体  
        for(int i=1;i<100;i++){   //让i循环99次  
            for(int j=1;j<=i;j++){  
                if(i==10){  
                    break OK ;  
                }  
                System.out.print(i + "*" + j + "=" + i*j) ;  
                System.out.print(" ") ;  
            }  
            System.out.println() ;  
        }  
    }  
}

16.构造器(constructor)是否可被重写(override)? 
答:构造器不能被继承,因此不能被重写,但可以被重载。

17.两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对? 
答:不对,如果两个对象x和y满足x.equals(y) == true,它们的哈希码(hash code)应当相同。Java对于eqauls方法和hashCode方法是这样规定的:(1)如果两个对象相同(equals方法返回true),那么它们的hashCode值一定要相同;(2)如果两个对象的hashCode相同,它们并不一定相同。当然,你未必要按照要求去做,但是如果你违背了上述原则就会发现在使用容器时,相同的对象可以出现在Set集合中,同时增加新元素的效率会大大下降(对于使用哈希存储的系统,如果哈希码频繁的冲突将会造成存取性能急剧下降)。

18.是否可以继承String类? 
答:String 类是final类,不可以被继承。

19.当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递? 
答:是值传递。Java语言的方法调用只支持参数的值传递。当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用。

20.String和StringBuilder、StringBuffer的区别? 

Java平台提供了两种类型的字符串:String和StringBuffer/StringBuilder,它们可以储存和操作字符串。其中String是只读字符串,也就意

味着String引用的字符串内容是不能被改变的。而StringBuffer/StringBuilder类表示的字符串对象可以直接进行修改。StringBuffer是线程

安全的,而StringBuilder是线程不安全的。

21.重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分? 
答:方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载;重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的返回类型、参数列表,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)。重载对返回类型没有特殊的要求。

22.描述一下JVM加载class文件的原理机制? 

23.抽象类(abstract class)和接口(interface)有什么异同? 

(1)抽象类和接口都不能被实例化,但是可以定义抽象类和接口的引用。

(2)抽象类中可以定义构造器,可以有抽象方法和具体方法,而接口中不能定义构造器而且其中的方法全部都是抽象方法。

(3)抽象类中的成员可以是private、默认、protected、public的,而接口中的成员全都是public的。抽象类中可以定义成员变量,而接口中定义的成员变量实际上都是常量。

24.静态嵌套类(Static Nested Class)和内部类(Inner Class)的不同? 

Static Nested Class是被声明为静态(static)的内部类,它可以不依赖于外部类实例被实例化。而通常的内部类需要在外部类实例化后才能实例化。

面试题,下面的代码哪些地方会产生编译错误

class Outer {
class Inner {}
 public static void foo() { new Inner(); }
public void bar() { new Inner(); }
public static void main(String[] args) {
        new Inner();
    }
}

Java中非静态内部类对象的创建要依赖其外部类对象,上面的面试题中foo和main方法都是静态方法,静态方法中没有this,也就是说没有所谓的外部类对象,因此无法创建内部类对象,如果要在静态方法中创建内部类对象,可以这样做:
new Outer().new Inner();

25.Java 中会存在内存泄漏吗,请简单描述

理论上Java因为有垃圾回收机制(GC)不会存在内存泄露问题;然而在实际开发中,可能会存在无用但可达的对象,这些对象不能被GC回收,因此也会导致内存泄露的发生。例如hibernate的Session(一级缓存)中的对象属于持久态,垃圾回收器是不会回收这些对象的,然而这些对象中可能存在无用的垃圾对象,如果不及时关闭(close)或清空(flush)一级缓存就可能导致内存泄露。

26.抽象的(abstract)方法是否可同时是静态的(static),是否可同时是本地方法(native),是否可同时被synchronized修饰? 
答:都不能。抽象方法需要子类重写,而静态的方法是无法被重写的,因此二者是矛盾的。本地方法是由本地代码(如C代码)实现的方法,而抽象方法是没有实现的,也是矛盾的。synchronized和方法的实现细节有关,抽象方法不涉及实现细节,因此也是相互矛盾的。

27.阐述静态变量和实例变量的区别

静态变量是被static修饰符修饰的变量,也称为类变量,它属于类,不属于类的任何一个对象,一个类不管创建多少个对象,静态变量在内存中有且仅有一个拷贝;实例变量必须依存于某一实例,需要先创建对象然后通过对象才能访问到它。静态变量可以实现让多个对象共享内存。

28.是否可以从一个静态(static)方法内部发出对非静态(non-static)方法的调用? 
答:不可以,静态方法只能访问静态成员,因为非静态方法的调用要先创建对象,在调用静态方法时可能对象并没有被初始化。

29.如何实现对象克隆? 
答:有两种方式: 
  1). 实现Cloneable接口并重写Object类中的clone()方法;(浅度克隆) 
  2). 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。

深度克隆和浅度克隆的区别:克隆的成员变量如果有引用类型和属性,克隆时是不会把引用类型和属性一起克隆的;深度克隆就是可以

         把引用类型和属性克隆出来,如图:


代码示例如下:

       import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;


public class MyUtil {


    private MyUtil() {
        throw new AssertionError();
    }
    @SuppressWarnings("unchecked")
    public static <T extends Serializable> T clone(T obj) throws Exception {
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bout);
        oos.writeObject(obj);


        ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bin);
        return (T) ois.readObject();


        // 说明:调用ByteArrayInputStream或ByteArrayOutputStream对象的close方法没有任何意义
        // 这两个基于内存的流只要垃圾回收器清理对象就能够释放资源,这一点不同于对外部资源(如文件流)的释放
    }
}

 import java.io.Serializable;


/**
 * 人类
 * @author 骆昊
 *
 */
class Person implements Serializable {
    private static final long serialVersionUID = -9102017020286042305L;


    private String name;    // 姓名
    private int age;        // 年龄
    private Car car;        // 座驾


    public Person(String name, int age, Car car) {
        this.name = name;
        this.age = age;
        this.car = car;
    }


    public String getName() {
        return name;
    }


    public void setName(String name) {
        this.name = name;
    }


    public int getAge() {
        return age;
    }


    public void setAge(int age) {
        this.age = age;
    }


    public Car getCar() {
        return car;
    }


    public void setCar(Car car) {
        this.car = car;
    }


    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + ", car=" + car + "]";
    }


}

/**
 * 小汽车类
 * @author 骆昊
 *
 */
class Car implements Serializable {
    private static final long serialVersionUID = -5713945027627603702L;


    private String brand;       // 品牌
    private int maxSpeed;       // 最高时速


    public Car(String brand, int maxSpeed) {
        this.brand = brand;
        this.maxSpeed = maxSpeed;
    }


    public String getBrand() {
        return brand;
    }


    public void setBrand(String brand) {
        this.brand = brand;
    }


    public int getMaxSpeed() {
        return maxSpeed;
    }


    public void setMaxSpeed(int maxSpeed) {
        this.maxSpeed = maxSpeed;
    }


    @Override
    public String toString() {
        return "Car [brand=" + brand + ", maxSpeed=" + maxSpeed + "]";
    }


}


class CloneTest {


    public static void main(String[] args) {
        try {
            Person p1 = new Person("Hao LUO", 33, new Car("Benz", 300));
            Person p2 = MyUtil.clone(p1);   // 深度克隆
            p2.getCar().setBrand("BYD");
            // 修改克隆的Person对象p2关联的汽车对象的品牌属性
            // 原来的Person对象p1关联的汽车不会受到任何影响
            // 因为在克隆Person对象时其关联的汽车对象也被克隆了
            System.out.println(p1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

30.String s = new String("xyz");创建了几个字符串对象? 
答:两个对象,一个是静态区的"xyz",一个是用new创建在堆上的对象

31.接口是否可继承(extends)接口?抽象类是否可实现(implements)接口?抽象类是否可继承具体类(concrete class)? 
答:接口可以继承接口,而且支持多重继承。抽象类可以实现(implements)接口,抽象类可继承具体类也可以继承抽象类。

32.Anonymous Inner Class(匿名内部类)是否可以继承其它类?是否可以实现接口? 
答:可以继承其他类或实现其他接口

33.内部类可以引用它的包含类(外部类)的成员吗?有没有什么限制? 
答:一个内部类对象可以访问创建它的外部类对象的成员,包括私有成员。

34.Java 中的final关键字有哪些用法? 
答:(1)修饰类:表示该类不能被继承;

(2)修饰方法:表示方法不能被重写;

(3)修饰变量:表示变量只能一次赋值以后值不能被修改(常量)。

35.指出下面程序的运行结果

     class A {


    static {
        System.out.print("1");
    }


    public A() {
        System.out.print("2");
    }
}


class B extends A{


    static {
        System.out.print("a");
    }


    public B() {
        System.out.print("b");
    }
}


public class Hello {


    public static void main(String[] args) {
        A ab = new B();
        ab = new B();
    }


}

执行结果:1a2b2b。创建对象时构造器的调用顺序是:先初始化静态成员,然后调用父类构造器,再初始化非静态成员,最后调用自身构

造器。

36.数据类型之间的转换: 
- 如何将字符串转换为基本数据类型? 
- 如何将基本数据类型转换为字符串? 
答:  调用基本数据类型对应的包装类中的方法parseXXX(String)或valueOf(String)即可返回相应基本类型; 

37.如何实现字符串的反转及替换

 public static String reverse(String originStr) {
        if(originStr == null || originStr.length() <= 1) 
            return originStr;
        return reverse(originStr.substring(1)) + originStr.charAt(0);
    }

38.怎样将GB2312编码的字符串转换为ISO-8859-1编码的字符串? 

String s1 = "你好";

String s2 = newString(s1.getBytes("GB2312"),"ISO-8859-1");

39.日期和时间: 
- 如何取得年月日、小时分钟秒? 
- 如何取得从1970年1月1日0时0分0秒到现在的毫秒数? 
- 如何取得某月的最后一天? 
- 如何格式化日期?

问题一:

public class DateTimeTest {
    public static void main(String[] args) {
        Calendar cal = Calendar.getInstance();
        System.out.println(cal.get(Calendar.YEAR));
        System.out.println(cal.get(Calendar.MONTH));    // 0 - 11
        System.out.println(cal.get(Calendar.DATE));
        System.out.println(cal.get(Calendar.HOUR_OF_DAY));
        System.out.println(cal.get(Calendar.MINUTE));
        System.out.println(cal.get(Calendar.SECOND));


        // Java 8
        LocalDateTime dt = LocalDateTime.now();
        System.out.println(dt.getYear());
        System.out.println(dt.getMonthValue());     // 1 - 12
        System.out.println(dt.getDayOfMonth());
        System.out.println(dt.getHour());
        System.out.println(dt.getMinute());
        System.out.println(dt.getSecond());
    }
}

问题二:

Calendar.getInstance().getTimeInMillis();
System.currentTimeMillis();

问题三:

Calendar time = Calendar.getInstance();
time.getActualMaximum(Calendar.DAY_OF_MONTH);

问题四:

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Date;


class DateFormatTest {


    public static void main(String[] args) {
        SimpleDateFormat oldFormatter = new SimpleDateFormat("yyyy/MM/dd");
        Date date1 = new Date();
        System.out.println(oldFormatter.format(date1));


        // Java 8
        DateTimeFormatter newFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
        LocalDate date2 = LocalDate.now();
        System.out.println(date2.format(newFormatter));
    }
}

40.打印昨天的当前时刻

import java.util.Calendar;


class YesterdayCurrent {
    public static void main(String[] args){
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, -1);
        System.out.println(cal.getTime());
    }
}

41.比较一下Java和JavaSciprt

基于对象和面向对象:Java是一种真正的面向对象的语言,即使是开发简单的程序,必须设计对象;JavaScript是种脚本语言,它可以用来制作与网络无关的,与用户交互作用的复杂软件

解释和编译:Java的源代码在执行之前,必须经过编译。JavaScript是一种解释性编程语言,其源代码不需经过编译,由浏览器解释执行

强类型变量和类型弱变量:Java采用强类型变量检查,即所有变量在编译之前必须作声明;JavaScript中变量是弱类型的,甚至在使用变量前可以不作声明

42.断言

断言在软件开发中是一种常用的调试方式,断言检查通常在开发和测试时开启。为了保证程序的执行效率,在软件发布后断言检查通常是关闭的。断言是一个包含布尔表达式的语句,在执行这个语句时假定该表达式为true;如果表达式的值为false,那么系统会报告一个AssertionError。

断言可以有两种形式: 
assert Expression1; 
assert Expression1 : Expression2 

Expression1:一个布尔表达式。

Expression2:断言失败时输出失败消息的字符串。

43.Error和Exception有什么区别

Error表示系统级的错误和程序不必处理的异常,是恢复不是不可能但很困难的情况下的一种严重问题;比如内存溢出,不可能指望程序能处理这样的情况;Exception表示需要捕捉或者需要程序进行处理的异常,是一种设计或实现问题;也就是说,它表示如果程序运行正常,从不会发生的情况

44.try{}里有一个return语句,那么紧跟在这个try后的finally{}里的代码会不会被执行,什么时候被执行,在return前还是后? 

会执行,在return之前执行。

45.throw 和 throws 的区别

throw是语句抛出一个异常,throws 是方法抛出一个异常

46.运行时异常与受检异常有何异同?

运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误,只要程序设计得没有问题通常就不会发生。受检异常跟程序运行的上下文环境有关,即使程序设计无误,仍然可能因使用的问题而引发。Java编译器要求方法必须声明抛出可能发生的受检异常,但是并不要求必须声明抛出未被捕获的运行时异常

47.列出一些你常见的运行时异常

ArithmeticException(算术异常) 
ClassCastException (类转换异常) 
IllegalArgumentException (非法参数异常) 
IndexOutOfBoundsException (下标越界异常) 
NullPointerException (空指针异常) 
SecurityException (安全异常)

48.阐述final、finally、finalize的区别

final:修饰符(关键字)有三种用法:如果一个类被声明为final,意味着它不能再派生出新的子类,即不能被继承,因此它和abstract是反义词。将变量声明为final,可以保证它们在使用中不被改变,被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取不可修改。被声明为final的方法也同样只能使用,不能在子类中被重写。 
- finally:通常放在try…catch…的后面构造总是执行代码块,这就意味着程序无论正常执行还是发生异常,这里的代码只要JVM不关闭都能执行,可以将释放外部资源的代码写在finally块中。 
- finalize:Object类中定义的方法,Java中允许使用finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在销毁对象时调用的,通过重写finalize()方法可以整理系统资源或者执行其他清理工作。

49.类ExampleA继承Exception,类ExampleB继承ExampleA

try {
    throw new ExampleB("b")
} catch(ExampleA e){
    System.out.println("ExampleA");
} catch(Exception e){
    System.out.println("Exception");
}

该代码执行之后返回什么?

答:返回ExampleA。能使用父类型的地方一定能使用子类型。

50.List、Set、Map是否继承自Collection接口

List、Set 是,Map 不是,List 元素有序可重复,Set的元素无序不可重复,Map键值对,键不可以重复。

51.阐述ArrayList、Vector、LinkedList的存储性能和特性

ArrayList和Vector都是使用数组的方式存储数据,而LinkedList是以链表的方式存储数据。所以ArrayList和Vector索引快而增删改慢,而

LinkedList增删改快,索引慢。Vector是线程安全的而ArrayList是线程不安全的。

52.Collection和Collections的区别

Collection是一个接口,它是Set、List等容器的父接口;Collections是个一个工具类,提供了一系列的静态方法来辅助容器操作,这些方法包括对容器的搜索、排序、线程安全化等等。

53.List、Map、Set三个接口存取元素时,各有什么特点

List以特定索引来存取元素,可以有重复元素。Set不能存放重复元素(用对象的equals()方法来区分元素是否重复)。Map保存键值对(key-value pair)映射,映射关系可以是一对一或多对一。

54.TreeMap和TreeSet在排序时如何比较元素?Collections工具类中的sort()方法如何比较元素? 

答:(1)TreeSet要求存放的对象所属的类必须实现Comparable接口,该接口提供了比较元素的compareTo()方法,当插入元素时会回调该方法比较元素的大小。TreeMap要求存放的键值对映射的键必须实现Comparable接口从而根据键对元素进行排序。

(2)Collections工具类的sort方法有两种重载的形式,第一种要求传入的待排序容器中存放的对象比较实现Comparable接口以实现元素的比较;第二种不强制性的要求容器中的元素必须可比较,但是要求传入第二个参数,参数是Comparator接口的子类型(需要重写compare方法实现元素的比较),相当于一个临时定义的排序规则,其实就是通过接口注入比较元素大小的算法,也是对回调模式的应用

例子1:

public class Student implements Comparable<Student> {
    private String name;        // 姓名
    private int age;            // 年龄


    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }


    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }


    @Override
    public int compareTo(Student o) {
        return this.age - o.age; // 比较年龄(年龄的升序)
    }


}

import java.util.Set;
import java.util.TreeSet;


class Test01 {


    public static void main(String[] args) {
        Set<Student> set = new TreeSet<>();     // Java 7的钻石语法(构造器后面的尖括号中不需要写类型)
        set.add(new Student("Hao LUO", 33));
        set.add(new Student("XJ WANG", 32));
        set.add(new Student("Bruce LEE", 60));
        set.add(new Student("Bob YANG", 22));


        for(Student stu : set) {
            System.out.println(stu);
        }
//      输出结果: 
//      Student [name=Bob YANG, age=22]
//      Student [name=XJ WANG, age=32]
//      Student [name=Hao LUO, age=33]
//      Student [name=Bruce LEE, age=60]
    }
}

例子2

public class Student {
    private String name;    // 姓名
    private int age;        // 年龄


    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }


    /**
     * 获取学生姓名
     */
    public String getName() {
        return name;
    }


    /**
     * 获取学生年龄
     */
    public int getAge() {
        return age;
    }


    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }


}

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;


class Test02 {


    public static void main(String[] args) {
        List<Student> list = new ArrayList<>();     // Java 7的钻石语法(构造器后面的尖括号中不需要写类型)
        list.add(new Student("Hao LUO", 33));
        list.add(new Student("XJ WANG", 32));
        list.add(new Student("Bruce LEE", 60));
        list.add(new Student("Bob YANG", 22));


        // 通过sort方法的第二个参数传入一个Comparator接口对象
        // 相当于是传入一个比较对象大小的算法到sort方法中
        // 由于Java中没有函数指针、仿函数、委托这样的概念
        // 因此要将一个算法传入一个方法中唯一的选择就是通过接口回调
        Collections.sort(list, new Comparator<Student> () {


            @Override
            public int compare(Student o1, Student o2) {
                return o1.getName().compareTo(o2.getName());    // 比较学生姓名
            }
        });


        for(Student stu : list) {
            System.out.println(stu);
        }
//      输出结果: 
//      Student [name=Bob YANG, age=22]
//      Student [name=Bruce LEE, age=60]
//      Student [name=Hao LUO, age=33]
//      Student [name=XJ WANG, age=32]
    }
}

55.Thread类的sleep()方法和对象的wait()方法都可以让线程暂停执行,它们有什么区别? 

sleep()方法会让当前线程暂停执行指定的时间,将执行机会(CPU)让给其他线程,但是对象的锁依然保持,因此休眠时间结束后会自动恢复。wait()是Object类的方法,调用对象的wait()方法导致当前线程放弃对象的锁(线程暂停执行),进入对象的等待池(wait pool),只有调用对象的notify()方法(或notifyAll()方法)时才能唤醒等待池中的线程进入等锁池(lock pool)

56.线程的sleep()方法和yield()方法有什么区别? 

① sleep()方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会;yield()方法只会给相同优先级或更高优先级的线程以运行的机会; 
② 线程执行sleep()方法后转入阻塞(blocked)状态,而执行yield()方法后转入就绪(ready)状态; 
③ sleep()方法声明抛出InterruptedException,而yield()方法没有声明任何异常; 
④ sleep()方法比yield()方法(跟操作系统CPU调度相关)具有更好的可移植性。

57.当一个线程进入一个对象的synchronized方法A之后,其它线程是否可进入此对象的synchronized方法B? 
答:不能。其它线程只能访问该对象的非同步方法,同步方法则不能进入。因为非静态方法上的synchronized修饰符要求执行方法时要获得对象的锁,如果已经进入A方法说明对象锁已经被取走,那么试图进入B方法的线程就只能在等锁池(注意不是等待池哦)中等待对象的锁。

58.请说出与线程同步以及线程调度相关的方法。

 wait():使一个线程处于等待(阻塞)状态,并且释放所持有的对象的锁; 
- sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要处理InterruptedException异常; 
- notify():唤醒一个处于等待状态的线程,当然在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且与优先级无关; 
- notityAll():唤醒所有处于等待状态的线程,该方法并不是将对象的锁给所有线程,而是让它们竞争,只有获得锁的线程才能进入就绪状态;

59.编写多线程程序有几种实现方式?

(1)Runable接口

package com.test.thread;  
  
import java.lang.management.ThreadInfo;  
  
public class MyThread implements Runnable {  
  
    String name=null;  
    MyThread(String name)  
    {  
        this.name=name;  
    }  
    @Override  
    public void run() {  
        // TODO Auto-generated method stub  
            while(true)  
            {  
                System.out.println(name+":输出结果...");  
            }  
    }  
  
}

package com.test.thread;  
  
public class Main {  
  
    /** 
     * @param args 
     */  
    public static void main(String[] args) {  
        // TODO Auto-generated method stub  
        MyThread mya=new MyThread("线程A");  
        Thread testA=new Thread(mya);  
        testA.start();  
          
        MyThread myb=new MyThread("线程B");  
        Thread testB=new Thread(myb);  
        testB.start();  
          
    }  
  
}  

(2)继承Thread类

public class MyThread extends Thread {  
  public void run() {  
   System.out.println("MyThread.run()");  
  }  
}  
 
MyThread myThread1 = new MyThread();  
MyThread myThread2 = new MyThread();  
myThread1.start();  
myThread2.start(); 

(3)Callable接口通过FutureTask

(4)线程池

import java.util.concurrent.*;  
import java.util.Date;  
import java.util.List;  
import java.util.ArrayList;  
  
/** 
* 有返回值的线程 
*/  
@SuppressWarnings("unchecked")  
public class Test {  
public static void main(String[] args) throws ExecutionException,  
    InterruptedException {  
   System.out.println("----程序开始运行----");  
   Date date1 = new Date();  
  
   int taskSize = 5;  
   // 创建一个线程池  
   ExecutorService pool = Executors.newFixedThreadPool(taskSize);  
   // 创建多个有返回值的任务  
   List<Future> list = new ArrayList<Future>();  
   for (int i = 0; i < taskSize; i++) {  
    Callable c = new MyCallable(i + " ");  
    // 执行任务并获取Future对象  
    Future f = pool.submit(c);  
    // System.out.println(">>>" + f.get().toString());  
    list.add(f);  
   }  
   // 关闭线程池  
   pool.shutdown();  
  
   // 获取所有并发任务的运行结果  
   for (Future f : list) {  
    // 从Future对象上获取任务的返回值,并输出到控制台  
    System.out.println(">>>" + f.get().toString());  
   }  
  
   Date date2 = new Date();  
   System.out.println("----程序结束运行----,程序运行时间【"  
     + (date2.getTime() - date1.getTime()) + "毫秒】");  
}  
}  
  
class MyCallable implements Callable<Object> {  
private String taskNum;  
  
MyCallable(String taskNum) {  
   this.taskNum = taskNum;  
}  
  
public Object call() throws Exception {  
   System.out.println(">>>" + taskNum + "任务启动");  
   Date dateTmp1 = new Date();  
   Thread.sleep(1000);  
   Date dateTmp2 = new Date();  
   long time = dateTmp2.getTime() - dateTmp1.getTime();  
   System.out.println(">>>" + taskNum + "任务终止");  
   return taskNum + "任务返回运行结果,当前任务时间【" + time + "毫秒】";  
}  
}  

60.启动一个线程是调用run()还是start()方法?

使用start()方法。调用start()方法无需等待run方法体代码执行完毕,可以直接继续执行下面的代码;调用run方法,要等待run方法体执行完毕后,才可

继续执行下面的代码。

61.什么是线程池(thread pool)?

答:在面向对象编程中,创建和销毁对象是很费时间的,所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁,这就是”池化资源”技术产生的原因。线程池就是事先创建若干个可执行的线程放入一个池(容器)中,需要的时候从池中获取线程不用自行创建,使用完毕不需要销毁线程而是放回池中,从而减少创建和销毁线程对象的开销。

62.简述synchronized 和java.util.concurrent.locks.Lock的异同?

Lock是Java 5以后引入的新的API,和关键字synchronized相比主要相同点:Lock 能完成synchronized所实现的所有功能;主要不同点:Lock有比synchronized更精确的线程语义和更好的性能,而且不强制性的要求一定要获得锁。synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且最好在finally 块中释放

63.Java中如何实现序列化,有什么意义?

序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决对象流读写操作时可能引发的问题。

要实现序列化,需要让一个类实现Serializable接口,该接口是一个标识性接口,标注该类对象是可被序列化的,然后使用一个输出流来构造一个对象输出流并通过writeObject(Object)方法就可以将实现对象写出(即保存其状态);如果需要反序列化则可以用一个输入流建立对象输入流,然后通过readObject方法从流中读取对象。序列化除了能够实现对象的持久化之外,还能够用于对象的深度克隆

64.Java中有几种类型的流?

字节流和字符流。字节流继承于InputStream、OutputStream,字符流继承于Reader、Writer。

65.写一个方法,输入一个文件名和一个字符串,统计这个字符串在这个文件中出现的次数。
答:代码如下

import java.io.BufferedReader;
import java.io.FileReader;
 
public final class MyUtil {
 
    // 工具类中的方法都是静态方式访问的因此将构造器私有不允许创建对象(绝对好习惯)
    private MyUtil() {
        throw new AssertionError();
    }
 
    /**
     * 统计给定文件中给定字符串的出现次数
     * 
     * @param filename  文件名
     * @param word 字符串
     * @return 字符串在文件中出现的次数
     */
    public static int countWordInFile(String filename, String word) {
        int counter = 0;
        try (FileReader fr = new FileReader(filename)) {
            try (BufferedReader br = new BufferedReader(fr)) {
                String line = null;
                while ((line = br.readLine()) != null) {
                    int index = -1;
                    while (line.length() >= word.length() && (index = line.indexOf(word)) >= 0) {
                        counter++;
                        line = line.substring(index + word.length());
                    }
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return counter;
    }
 
}

66.如何用Java代码列出一个目录下所有的文件?

importjava.io.File;
 
classTest12 {
 
    publicstaticvoidmain(String[] args) {
        File f = newFile("/Users/Hao/Downloads");
        for(File temp : f.listFiles()) {
            if(temp.isFile()) {
                System.out.println(temp.getName());
            }
        }
    }
}

67.XML文档定义有几种形式?它们之间有何本质区别?解析XML文档有哪几种方式?
答:XML文档定义分为DTD和Schema两种形式,二者都是对XML语法的约束,其本质区别在于Schema本身也是一个XML文件,可以被XML解析器解析,而且可以为XML承载的数据定义类型,约束能力较之DTD更强大。对XML的解析主要有DOM(文档对象模型,Document Object Model)、SAX(Simple API for XML)和StAX(Java 6中引入的新的解析XML的方式,Streaming API for XML),其中DOM处理大型文件时其性能下降的非常厉害,这个问题是由DOM树结构占用的内存较多造成的,而且DOM解析方式必须在解析文件之前把整个文档装入内存,适合对XML的随机访问(典型的用空间换取时间的策略);SAX是事件驱动型的XML解析方式,它顺序读取XML文件,不需要一次全部装载整个文件。当遇到像文件开头,文档结束,或者标签开头与标签结束时,它会触发一个事件,用户通过事件回调代码来处理XML文件,适合对XML的顺序访问;顾名思义,StAX把重点放在流上,实际上StAX与其他解析方式的本质区别就在于应用程序能够把XML作为一个事件流来处理。将XML作为一组事件来处理的想法并不新颖(SAX就是这样做的),但不同之处在于StAX允许应用程序代码把这些事件逐个拉出来,而不用提供在解析器方便时从解析器中接收事件的处理程序。

68.Statement和PreparedStatement有什么区别?哪个性能更好?
与Statement相比,①PreparedStatement接口代表预编译的语句,它主要的优势在于可以减少SQL的编译错误并增加SQL的安全性(减少SQL注射攻击的可能性);②PreparedStatement中的SQL语句是可以带参数的,避免了用字符串连接拼接SQL语句的麻烦和不安全;③当批量处理SQL或频繁执行相同的查询时,PreparedStatement有明显的性能上的优势,由于数据库可以将编译优化后的SQL语句缓存起来,下次执行相同结构的语句时就会很快(不用再次编译和生成执行计划)

69.在进行数据库编程时,连接池有什么作用
由于创建连接和释放连接都有很大的开销(尤其是数据库服务器不在本地时,每次建立连接都需要进行TCP的三次握手,释放连接需要进行TCP四次握手,造成的开销是不可忽视的),为了提升系统访问数据库的性能,可以事先创建若干连接置于连接池中,需要时直接从连接池获取,使用结束时归还连接池而不必关闭连接,从而避免频繁创建和释放连接所造成的开销

70.事务的ACID是指什么
 原子性(Atomic):事务中各项操作,要么全做要么全不做,任何一项操作的失败都会导致整个事务的失败;
- 一致性(Consistent):事务结束后系统状态是一致的;
- 隔离性(Isolated):并发执行的事务彼此无法看到对方的中间状态;
- 持久性(Durable):事务完成后所做的改动都会被持久化,即使发生灾难性的失败。通过日志和同步备份可以在故障发生后重建数据。
关于原子性和一致性的区别:
张三给李四转账100元,需要先重张三的账户上减去100元,在给李四的账户上增加100元,如果张三减去100失败那么整个事物就回滚,这就是原子性的体现;假设张三李四的账户在转账前都是1000元,那么转账后张三账户为900元,李四账户为1100元,这就是一致性的体现。

71.脏读、不可重复读、幻影读。
脏读,读到了其他事务没有提交的数据
不可重复读,读到了其他事务修改的数据。
幻影读,读到了其他事务新增或是删除的数据。
隔离级别脏读不可重复读幻读
READ UNCOMMITED 允许 允许 允许
READ COMMITTED 不允许 允许 允许
REPEATABLE READ 不允许 不允许 允许
SERIALIZABLE 不允许 不允许 不允许 不允许

72.Java中是如何支持正则表达式操作的
Java中的String类提供了支持正则表达式操作的方法,包括:matches()、replaceAll()、replaceFirst()、split()。此外,Java中可以用Pattern类表示正则表达式对象,它提供了丰富的API进行各种正则表达式操作

73.获得一个类的类对象有哪些方式
方法1:类型.class,例如:String.class
- 方法2:对象.getClass(),例如:”hello”.getClass()
- 方法3:Class.forName(),例如:Class.forName(“java.lang.String”)
74.UML中有哪些常用的图
用例图,时序图,类图这三个有空优先看
75.redirect和forward区别
重浏览器地址栏来说,forward浏览器地址栏不会发生变化,而redirect地址栏会发生变化
重request共享来说,forward转发页面和转发到的页面可以共享request里面的数据.,而redirect不能。
重效率来说,redirect低,forward高。
本质forward是同一请求,forward是不同的qing'qi
76.<%@ include file=""%>和<jsp:include page="" flush="true"/>的区别
<%@ include file=""%>和原jsp融合在一起,是在编译阶段进行的,而<jsp:include page="" flush="true"/>和原Jsp融合在一起是在
运行阶段进行的;重翻译成Servlet的角度来说<%@ include file=""%>翻译成一个Servlet而<jsp:include page="" flush="true"/>翻译
成多个Servlet
77.JSP内置对象
- request:javax.servlet.http.HttpServletRequest; 
- response: javax.servlet.http.HttpServletResponse; 
- pageContext:javax.servlet.jsp.PageContext; 
- session: javax.servlet.http.HttpSession
- application:javax.servlet.ServletContext; 
- out:javax.servlet.jsp.jspWriter; 
- config:avax.servlet.ServletConfig; 
page:java.lang.Object; 
- exception:java.lang.Throwable。
78.get和post请求的区别

(1)get请求用来从服务器上获得资源,而post是用来向服务器提交数据; 
(2)get将表单中数据按照name=value的形式明文传递,添加到action 所指向的URL 后面,并且两者使用"?"连接,而各个变量之间使用"&"连接;post是将表单中的数据放在HTTP协议的请求头或消息体中,传递到action所指向URL; 
(3)get传输的数据要受到URL长度限制(1024字节);而post可以传输大量的数据,上传文件通常要使用post方式; 
(4)get是安全幂等的而post不是
(5)GET是获取指定URL上的资源,是读操作,重要的一点是不论对某个资源GET多少次,它的状态是不会改变的所以说GET是安全的内容可以被浏览器,Cache服务器缓存起来
而post是语义上市“追加/添加”数据,所以是不安全的,每次提交的POST,参与的代码都会认为这个操作会修改操作对象资源的状态,所以Post是不安全的,它的内容不会被浏览器Cache
服务器缓存起来
参考题目答案和博客http://blog.csdn.net/apple_hsp/article/details/50765629
79.讲解JSP中的四种作用域
page、request、session和application
page代表与一个页面相关的对象和属性。 
- request代表与Web客户机发出的一个请求相关的对象和属性。一个请求可能跨越多个页面,涉及多个Web组件;需要在页面显示的临时数据可以置于此作用域。 
- session代表与某个用户与服务器建立的一次会话相关的对象和属性。跟某个用户相关的数据应该放在用户自己的session中。 
- application代表与整个Web应用程序相关的对象和属性,它实质上是跨越整个Web应用程序,包括多个页面、请求和会话的一个全局作用域。
80.如何实现JSP或Servlet的单线程模式
<%@page isThreadSafe=”false”%>
81.过滤器有哪些作用和用法
过滤器是一个驻留在服务器端的Web组件,它可以截取客户端和服务器之间的请求与响应信息,并对这些信息进行过滤。
其主要用处包括:对用户请求进行统一认证、对用户的访问请求进行记录和审核、对用户发送的数据进行过滤或替换、转换图象格式、对响应内容进行压缩以减少传输量、对请求或响应进行加解密处理、触发资源访问事件、对XML的输出应用XSLT等。
82.监听器有哪些作用和用法
ServletContextListener:对Servlet上下文的创建和销毁进行监听。 
②ServletContextAttributeListener:监听Servlet上下文属性的添加、删除和替换。 
③HttpSessionListener:对Session的创建和销毁进行监听。
④HttpSessionAttributeListener:对Session对象中属性的添加、删除和替换进行监听。 
⑤ServletRequestListener:对请求对象的初始化和销毁进行监听。 
⑥ServletRequestAttributeListener:对请求对象属性的添加、删除和替换进行监听。
83.web.xml文件中可以配置哪些内容
web.xml用于配置Web应用的相关信息,如:监听器(listener)、过滤器(filter)、 Servlet、相关参数、会话超时时间、安全验证方式、错误页面等
84.Java Web开发的Model 1和Model 2分别指的是什么
JSP+JavaBean就是model1,mvc是model2
85.JSP中的静态包含和动态包含有什么区别
<%-- 静态包含 --%>
<%@ include file="..." %>


<%-- 动态包含 --%>
<jsp:include page="...">
    <jsp:param name="..." value="..." />
</jsp:include>
86.Servlet中如何获取用户提交的查询参数或表单数据
可以通过请求对象(HttpServletRequest)的getParameter()方法通过参数名获得参数值。如果有包含多个值的参数(例如复选框),可以通过请求对象的getParameterValues()方法获得。当然也可以通过请求对象的getParameterMap()获得一个参数名和参数值的映射(Map)

86.webService 待看
87.MyBatis中使用#和$书写占位符有什么区别?
#将传入的数据都当成一个字符串,会对传入的数据自动加上引号;$将传入的数据直接显示生成在SQL中。注意:使用$占位符可能会导致SQL注射攻击,能用#的地方就不要使用$,写order by子句的时候应该用$而不是#

88.什么是IoC和DI?DI是如何实现的

89.Spring中Bean的作用域有哪些?
singleton和prototype,前者表示Bean以单例的方式存在;后者表示每次从容器中调用Bean时,都会返回一个新的实例

90.解释一下什么叫AOP(面向切面编程)
AOP(Aspect-Oriented Programming)指一种程序设计范型,该范型以一种称为切面(aspect)的语言构造为基础,切面是一种新的模块化机制,用来描述分散在对象、类或方法中的横切关注点(crosscutting concern)。

91.Spring中自动装配的方式有哪些
no:不进行自动装配,手动设置Bean的依赖关系。
- byName:根据Bean的名字进行自动装配。
- byType:根据Bean的类型进行自动装配。
- constructor:类似于byType,不过是应用于构造器的参数,如果正好有一个Bean与构造器的参数类型相同则可以自动装配,否则会导致错误。
- autodetect:如果有默认的构造器,则通过constructor的方式进行自动装配,否则使用byType的方式进行自动装配。

92.Spring支持的事务管理类型有哪些?你在项目中使用哪种方式
pring支持编程式事务管理和声明式事务管理。许多Spring框架的用户选择声明式事务管理,因为这种方式和应用程序的关联较少,因此更加符合轻量级容器的概念。声明式事务管理要优于编程式事务管理,尽管在灵活性方面它弱于编程式事务管理,因为编程式事务允许你通过代码控制业务

93.SpringMvc的工作原理
客户端请求提交到DispatcherServlet
由DispatcherServlet控制器查询一个或多个HandlerMapping,找到处理请求的Controller
DispatcherServlet将请求提交到Controller
Controller调用业务逻辑处理后,返回ModelAndView
DispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModelAndView指定的视图
视图负责将结果显示到客户端

94.Struts2和spring区别
(1)Struts2是类级别的拦截,一个类对应一个request上下文,Spring Mvc是方法级别的拦截,一个方法对应一
Request上下文,所以Spring Mvc更容易实现restful url。
(2)Spring Mvc方法间是独立的独享Request Response 数据,方法间不能共享变量,而Struts2 的Action 变量
是共享的,所以Spring Mvc编码更简洁。
(3)Struts徐要对Request,Session 等Servlet生命周期的对象进行封装提供给Action使用,并保证线程安全,所以
Struts2的性能比较差。
(4)拦截器机制上Struts2有自己的拦截器,Spring Mvc使用独立的Aop,所以Spring Mvc的配置文件比Struts2
更简洁。
(5)入口上Struts2使用的是filter,Spring Mvc使用的是Servlet。
95.Redis和Memcache的区别

如果简单地比较RedisMemcached的区别,大多数都会得到以下观点:

(1)Redis
数据类型有StringhashlistsetzsetMemache只有string

(2)Redis支持数据的备份,即master-slave模式的数据备份。
(3)Redis
支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用,

(4)Redis是单线程的而memcache是多线程的

memcache只能存在于内存中。

96.Tcp的三次握手和四次分手

l  TCP的三次握手

第一次握手:主机A发送位码为syn=1,随机产生seq number=1234567的数据包到服务器,主机B由SYN=1知道,

A要求建立联机;

第二次握手:主机B收到请求后要确认联机信息,向A发送ack number=(主机A的seq+1),syn=1,ack=1,随机产生

seq=7654321的包

第三次握手:主机A收到后检查ack number是否正确,即第一次发送的seq number+1,以及位码ack是否为1,若

正确,主机A会再发送ack number=(主机B的seq+1),ack=1,主机B收到后确认seq值与ack=1则连接建立成功。

完成三次握手,主机A与主机B开始传送数据。

l 四次分手

第一次分手:主机1,向主机2发送一个FIN报文段;此时,主机1进入FIN_WAIT_1状态;这表示主机1没有数据要发

送给主机2了;

第二次分手:主机2收到了主机1发送的FIN报文段,向主机1回一个ACK报文段,主机1进入FIN_WAIT_2状态;主机

2告诉主机1,我“同意”你的关闭请求;

第三次分手:主机2向主机1发送FIN报文段,请求关闭连接,同时主机2进入LAST_ACK状态;

第四次分手:主机1收到主机2发送的FIN报文段,向主机2发送ACK报文段,然后主机1进入TIME_WAIT状态;主机

2收到主机1的ACK报文段以后,就关闭连接;此时,主机1等待2MSL后依然没有收到回复,则证明Server端已正常

关闭,那好,主机1也可以关闭连接了。

97.zookeeper的节点类型

持久节点:需要执行删除的时候才删除

持久顺序节点:就是持久节点维护了一个时序

临时节点:生命周期同回话的生命周期

临时顺序节点:临时节点维护了一个时序

98.zookeeper的watch机制

98.ZAB协议

包括两个阶段

99.一个网站的架构


100.nginx的5种负载策略
(1)轮询
每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除
(2)指定权重
指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况
(3)IP绑定 ip_hash
每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。 
(4)4、fair(第三方)
按后端服务器的响应时间来分配请求,响应时间短的优先分配。 
(5)url_hash(第三方)
按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。 
101.nginx优化
worker_processes:置成cpu的总核数,或者其2倍,性能会更好。这可以减少进程间
切换带来的消耗。
(1)worker_cpu_affinity:绑定cpu
(2)worker_rlimit_nofile:描述一个nginx进程打开的最多的文件数目,配置成跟linux内核下文件打开数一致就可以了,ulimit -n查看linux
内核下文件打开数。
(3)worker_connections:每个进程允许的最多连接数,默认是1024,可以设置大一些
(4)keepalive_timeout:HTTP连接的持续时间,设置到65左右就可以
(5)client_header_buffer_size:请求的缓存,4k即可
(6)尽量开启Gzip压缩,gzip_comp_level通常设置成3-5,高了浪费CPU
(7)Error日志优化:运行期间设置为crit,可以减少I/O
(6)worker_priority:进程优先级,取值范围-20到+19,-20级别最高。因此可以把这个值设置小一点,但不建
议比内核进程的值低(通常为-5)
102.常见的网络攻击和防范手段
(1)XSS攻击:跨站脚本攻击,指攻击者在网页中嵌入恶意脚本程序,当用户,脚本程序便开始在客户端的浏览器
上执行,盗取客户端的cookie、用户名、密码、下载执行木马程序,甚至获取客户端的admin权限等。
例如<input type="text" name="nick" value="xiaomao">
恶意用户输入<script type="text">haha</script>
xss防范,对用户的输入的数据进行html转义处理,比如对<>、"" 、" 进行转义编码。很多开源的框架就支持html
代码转义的功能,如 Struts,jstl,不需要开发人员过多的开发
(2)CRSF攻击
首先用户C浏览并登陆了受信任站点A,登陆信息验证通过后站点B会在返回给浏览器的信息中带上已登陆的cookie,
cookie信息会在浏览器端保存一段时间,用户在没有退出站点A的情况下访问恶意站点B,这时恶意站点B的某个页面
向站点A发起请求,而这个请求会带上浏览器所保存站点A的Cookie,判断此请求为用户C所发送的。因此站点A会根
据用户C的权限来处理恶意站点B所发起的请求,而这个请求可能以用户C的身份发送邮件、短信、消息,以及进行转
账支付等操作,这样恶意站点B就达到了伪造用户C亲求站点A的目的。
CRSF防御
(a)将cookie设置成HttpOnly
(b)增加token
(c)Referer识别
(3)SQL注入攻击
使用PreparedStatement或是ORM框架。
(4)文件上传漏洞
上传时上传可执行的文件或是脚本诱导用户执行
防范:白名单(魔数-文件头校验),重命名;图片类型的可以上传后做相应的缩放破坏恶意文件的二进制结构,
使用imagemagick。
(5)DDos攻击:Dos攻击的升级版,攻击者借助公共网络,将数量庞大的计算机联合起来作为攻击平台,对一个
或多个目标发动攻击,重而达到瘫痪主机的目的。
书上没说怎么防范。
Dos攻击:利用合理的客户端请求来占用过多的服务器资源,从而使合法的用户无法得到服务器的响应。

103.sql优化
应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描
应尽量避免在 where 子句中对字段使用<> !=,否则将导致引擎放弃使用索引而进行全表扫描
用union all 替换or,因为在or中如果一个字段有索引 一个字段没有索引 那么会造成全表扫描
用exists代替in
尽量不要在字段上进行计算,这样会放弃索引例如:
select id from t where num/2 = 100应改为select id from t where num = 100*2
尽量不要在字段上使用函数操作
在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证
系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。
Update 语句,如果只更改1、2个字段,不要Update全部字段,否则频繁调用会引起明显的性能消耗,同时带来大
量日志
104.HashMap 、HashTable、ConcurrentHashMap区别
HashMap线程不安全、HashTable线程安全 、ConcurrentHashMap是锁住单个桶的,HashTable是锁整个结构的。ConcurrentHashMap支持
多个线程同时写入和读取,并发性能比较高








  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值