【十三】Java SE中的一些常见问题

目录

一、异常处理

二、comparable与comparator

1、实现Comparable:

2、实现Comparator接口:

三、Java编译时与运行时

四、hashCode()与equals()方法

五、finalize方法

六、面向对象、面向接口编程

七、String、StringBuffer、StringBuilder


一、异常处理

Error

是程序无法处理的错误,表示的是代码运行时JVM出现的问题,如OOM。

Exception

是程序可以处理的异常,他的子类RuntimeExcption代表运行时异常,除运行时异常以外的异常都是非运行时异常

unchecked exception(非检查异常)

也称作运行时异常,编译器不要求必须进行异常处理,由程序员自己决定,如NullPointerException,IndexOutOfBoundsExcption。

checked exception(检查异常,编译异常)

也称作非运行时异常(运行时异常以外的异常就是非运行时异常),编译器强制程序员必须进行处理,否则编译不会通过,比如常见的IOException和SQLException。

二、comparable与comparator

comparable是内比较器,写在类的里面

comparator是外比较器,和比较的类分开写,耦合性较低。可以重写实现了comparable接口的类当中的compareTo方法。

主要以下两种情况使用comparator:

1、一个对象不支持自己和自己比较(没有实现Comparable接口),但是又想对两个对象进行比较

2、一个对象实现了Comparable接口,但是开发者认为compareTo方法中的比较方式并不是自己想要的那种比较方式(重写已经被重写的compareTo方法,覆盖掉实现comparable接口的compareTo方法)

1、实现Comparable:

package testJavaInterfaceAndMethod;

public class Person implements  Comparable<Person>{//本类实现Comparable接口,内比较器方法只需要一个参数

    private int age;

    private String name;

    public Person() {

        

    }

    public Person(int age, String name) {

        super();

        this.age = age;

        this.name = name;

    }

    public int getAge() {

        return age;

    }

    public void setAge(int age) {

        this.age = age;

    }

    public String getName() {

        return name;

    }

    public void setName(String name) {

        this.name = name;

    }

    @Override

    public int compareTo(Person o) {

        return this.getAge()-o.getAge();

    }

    @Override

    public String toString() {

        return "Person [age=" + age + ", name="  + name + "]";

    }

}

2、实现Comparator接口:

package testJavaInterfaceAndMethod;

importjava.util.Comparator;

public class PersonComparator implements  Comparator<Person>{//外比较器,方法需要两个参数

//为什么不用重写Comparator中的所有抽象方法

    @Override

    public int compare(Person o1, Person o2) {

        return o2.getAge()-o1.getAge();//注意这里的顺序和实现Comparable接口的compareTo方法属性不一致。

    }

}

测试:

package testJavaInterfaceAndMethod;

import java.util.Arrays;

import org.junit.Test;

public class Main {

    @Test

    public void testComparable() {

        Person person1 = new Person(22,"dhl");

        Person person2 = new Person(21,"pj");

        Person[] persons = {person1,person2};

        for (int i = 0; i < persons.length; i++)  {

            System.out.println(persons[i]);

        }

        Arrays.sort(persons,new  PersonComparator());//使用外比较器的方法

        for (int i = 0; i < persons.length; i++)  {

            System.out.println(persons[i]);

        }

    }

}

结果:

Person [age=22, name=dhl]

Person [age=21, name=pj]

Person [age=22, name=dhl]

Person [age=21, name=pj]

同时使用内比较器与外比较器,外比较器优先

三、Java编译时与运行时

编译时:将源代码编译为JVM可以识别的字节码

运行时:将字节码装载到内存中运行。

例:

public class ConstantFolding {

static final int number1 = 5;

static final int number2 = 6;

static int number3 = 5;

static int number4= 6;

public static void main(String[ ] args) {

int product1 = number1 * number2; //line A

int product2 = number3 * number4; //line B

}

}

解析:

lineA 是在编译期间计算的。

lineB 是在运行期间计算的。

常量折叠是种Java编译器使用的优化技术。由于final变量的值不会改变,因此就可以对它们优化。

方法重载:这个是发生在编译时的。方法重载也被称为编译时多态,因为编译器可以根据参数的类型来选择使用哪个方法。

例:

public class {

public static void evaluate(String param1); // method #1

public static void evaluate(int param1); // method #2

}

方法覆盖:这个是在运行时发生的。方法重载被称为运行时多态,因为在编译期编译器不知道并且没法知道该去调用哪个方法。JVM会在代码运行的时候做出决定。

例:

public class A {

public int compute(int input) { //method #3

return 3 * input;

}

}

public class B extends A {

@Override

public int compute(int input) { //method #4

return 4 * input;

}

}

子类B中的compute(..)方法重写了父类的compute(..)方法。如果编译器遇到下面的代码:

public int evaluate(A reference, int arg2) {

int result = reference.compute(arg2);

}

编译器是没法知道传入的参数reference的类型是A还是B。因此,只能够在运行时,根据赋给输入变量“reference”的对象的类型(例如,A或者B的实例)来决定调用方法#3还是方法#4

泛型(又称类型检验):这个是发生在编译期的。编译器负责检查程序中类型的正确性,然后把使用了泛型的代码翻译或者重写成可以执行在当前JVM上的非泛型代码。这个技术被称为“类型擦除“。

换句话来说,编译器会擦除所有在尖括号里的类型信息,来保证和版本1.4.0或者更早版本的JRE的兼容性。

例:

编译前:

List<Person> myList = new ArrayList(10);

编译后: 

List myList = new ArrayList(10);

四、hashCode()与equals()方法

java的规定:如果两个对象 equals相等,那么hashCode一定相等(这里的equals和hashCode方法指的是没有重写的Object类中的方法, 未重写的equals()方法比较的是对象的地址(直接使用==比较)。

也就是说如果两个对象的地址相同,那么他们的hashCode一定相同,地址不同,那么就不一定了),但hashCode相等,对象不一定equals,hashCode不相等,那么对象一定不equals。

1.hashCode()方法存在的主要目的就是提高在散列结构存储中的查询效率。

如果没有hashCode方法的话,在HashMap中为了避免添加相同的key,那么有多少个元素就需要equals比较多少次,但是在如果有hachCode方法,就会先根据hashCode值找到对应的哈希桶,然后再进行equals比较,减少了比较的次数。

2.在set集合中判断两个对象相等的条件,其实无论是往set集合中存数据,还是从set集合中取数据,包括控制唯一性等,都是用这个条件判断的,条件如下:

    首先判断两个对象的hashCode是否相等,如果不相等,就认为这两个对象不相等,就完成了。如果相等,才会判断两个对象的equals()是否相等,如果不相等,就认为这两个对象不相等,如果相等,那就认为这两个对象相等。

所以为保证set集合中的元素的唯一性:

1、在重写了equals方法后应该重写hashCode方法(不重写hashCode方法,equals但hashCode不同,此时就会重复)

2、而只重写hashCode方法而不重写equals方法:会产生hashCode不相同,但是对象可能equals,还是会出现元素重复。

五、finalize方法

finalize是在java.lang.Object类中定义,这个方法在gc启动,该对象被回收之前被调用。其实gc可以回收大部分的对象,所以一般是不需要程序员去实现finalize的。在对象回收的时候需要释放资源,此时可以实现finalize()方法。

一个对象的finalize()方法只能被调用一次,而且finalize()方法被调用不意味着gc会立刻回收该对象,所以有可能调用finalize()后,该对象又不会被回收,到了真正回收对象的时候,因为之前已经调用过了,所以不会调用finalize()方法,由此产生问题。另外,finalize()方法会忽略异常,即finalize代码中若出现异常,异常会被忽略。推荐不要主动使用finalize()方法,它跟析构函数不一样(超过变量的使用范围自动调用析构,调用析构函数后变量被销毁)。

六、面向对象、面向接口编程

万物皆对象,现实生活中每一个物体都属于一类事物,而每一个个体都是一类事物的实例。

面向对象有三大特性,封装、继承和多态。

1、封装就是将一类事物的属性和行为抽象成一个类,使其属性私有化,行为公开化,提高了数据的隐秘性的同时,使代码模块化。这样做使得代码的复用性更高。

2、继承则是进一步将一类事物共有的属性和行为抽象成一个父类,而每一个子类是一个特殊的父类--有父类的行为和属性,也有自己特有的行为和属性。这样做扩展了已存在的代码块,进一步提高了代码的复用性。

3、如果说封装和继承是为了使代码重用,那么多态则是为了实现接口重用。多态的一大作用就是为了解耦--为了解除父子类继承的耦合度。如果说继承中父子类的关系式IS-A的关系,那么接口和实现类之之间的关系式HAS-A。简单来说,多态就是允许父类引用(或接口)指向子类(或实现类)对象。很多的设计模式都是基于面向对象的多态性设计的。

总结一下,如果说封装和继承是面向对象的基础,那么多态则是面向对象最精髓的理论。掌握多态必先了解接口,只有充分理解接口才能更好的应用多态。

面向接口编程:接口也就是一种规范!面向接口编程就类似于现实中遵守公司规定一样!这样增强了系统的灵活性、可维护性,减小影响!实现项目中常说的:高内聚、低耦合!

七、String、StringBuffer、StringBuilder

String 字符串常量;StringBuffer 字符串变量(线程安全);StringBuilder 字符串变量(非线程安全)

String S1 = “This is only a” + “ simple” + “ test”;

其实就是:String S1 = “This is only a simple test”

对于字符串经常改变时,速度:StringBuilder>StringBuffer>String

猜你喜欢

转载自blog.csdn.net/Jack_PJ/article/details/88038129