基础知识汇总

232 阅读4分钟

基本功

1.面向对象的特征

  • 抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象。抽象只关注对象有哪些属性和行为,而不去关心具体的细节。
  • 集成:从已有类得到继承信息创建新类的过程。提供继承信息的类称为父类(超类|基类);得到继承信息的类称为子类(派生类)。继承使得类之间有一定的延续性,同时也是封装程序中可变因素的重要手段。
  • 封装:隐藏一切可以隐藏的细节,只向外界提供最简单的接口。
  • 多态性:多态是指不同子类型的对象对同一消息作出不同的响应。多态性分为编译时的多态性和运行时的多态性。方法的重载(overload)是编译时的多态性;方法重写(override)是运行时的多态性。运行时的多态也是面向对象的最重要的内容。

2.final finally finalize的区别

final:修饰符有三种法。修饰一个类时:这个类便不能被继承,也就是不能派生出新的子类;修饰一个变量时:这个变量在使用中不可以被改变,且在声明的同时必须指定初值,并且在以后的引用中只能读取不可修改;修饰一个方法时:这个方法不可以在子类中重写。

3.重载和重写的区别

重载重写都是多态的一种表现。区别在于前者是编译时的多态性后者是运行时的多态性。重载是指在同一个类中,同名的方法有不同的参数列表,参数的个数不同,参数的类型不同,或者两者都不相同;重写发生在子类和父类之间,重写要求子类重写的方法与父类被重写的方法有相同的参数和返回值类型,不能比父类中声明更多的异常。而重载对返回值的类型没有要求,这是因为我们的使用方法的时候并不能指定返回值的类型而且返回值也是可以忽略的。

4.抽象类和接口有什么区别

抽象类接口都不能够实例化,但可以定义抽象类和接口类型的引用。一个类如果继承了某个抽象类或者实现了某个接口都需要对其中的抽象方法全部进行实现,否则该类仍然需要被声明为抽象类。接口比抽象类更加抽象,因为抽象类中可以定义构造器,可以有抽象方法和具体方法,而接口中不能定义构造器而且其中的方法全部都是抽象方法。抽象类中的成员可以是private、默认、protected、public的,而接口中的成员全都是public的。抽象类中可以定义成员变量,而接口中定义的成员变量实际上都是常量。有抽象方法的类必须被声明为抽象类,而抽象类未必要有抽象方法。

5.反射的用途及实现

  • 通过反射创建对象

A:通过类对象调用newInstance()方法 例如String.class.newInstance()
B:通过类对象的getConstructor()或者getDeclaredConstructor()方法获取构造器(Constructor)对象并调用newInstance()方法创建对象 例如String.class.getConstructor(String.class).newInstance("Hello");

  • 通过反射获取和设置对象的私有字段的值

通过类对象的getDeclaredField()方法获取字段(Field)对象,然后再通过字段的setAccessible(true)将其设为可以访问,接下来就可以通过get/set方法来获得和设置字段的值了

/**
     * 通过反射取对象指定字段的值
     * @param target
     * @param fieldName
     * @return
     */
    public static Object getValue(Object target,String fieldName){
        Class<?> clazz=target.getClass();
        String[] fs=fieldName.split("\\.");
        try {
            for(int i=0;i<fs.length-1;i++){
                Field f=clazz.getDeclaredField(fs[i]);
                f.setAccessible(true);
                target=f.get(target);
                clazz=target.getClass();
            }
            Field f=clazz.getDeclaredField(fs[fs.length-1]);
            f.setAccessible(true);
            return f.get(target);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 通过反射给对象的指定字段赋值
     * @param target
     * @param fieldName
     * @param value
     */
    public static void setValue(Object target,String fieldName,Object value){
        Class<?> clazz=target.getClass();
        String[] fs=fieldName.split("\\.");
        try {
            for(int i=0;i<fs.length-1;i++){
                Field f=clazz.getDeclaredField(fs[i]);
                f.setAccessible(true);
                Object val=f.get(target);
                //还未初始化
                if(val == null){

                    Constructor<?> c=f.getType().getDeclaredConstructor();
                    c.setAccessible(true);
                    val=c.newInstance();
                    f.set(target,val);
                }
                target=val;
                clazz=target.getClass();

            }

            Field f=clazz.getDeclaredField(fs[fs.length-1]);
            f.setAccessible(true);
            f.set(target,value);
        } catch (Exception e) {
           throw new RuntimeException(e);
        }
    }
  • 通过反射调用对象的方法

通过类的getMethod(methodName)方法获取指定的Method,然后根据method.invoke(obj)就可以运行对象的方法了

tring str = "hello";
Method m = str.getClass().getMethod("toUpperCase");
System.out.println(m.invoke(str)); // HELLO