"Java高级"-Java,Android面试必问部分

高级部分

大家好,前几天给大家写了一篇“java,Android面试必问的JAVA基础部分(点击访问)”,现在给出的是JAVA高级部分,如果你们能拿够掌握这两部分,那么在面试的过程中你们就会游刃有余了,后续还会给大家写出Android基础/高级部分”,希望能帮助有需要的朋友.

一.JAVA中的反射

对反射的理解

1.获取java反射类的字节码文件
2.获取的方法有三种
    1.Class.forName(类名)
    2.类名.getClass
    3.this.class
3.通过获取到的字节码,就能获取到其中的方法(methode),属性变量(File),构造函数(Coustructor)

代码

public class Invoke {
    public static void main(String[] args) throws Exception {
        invoke();
        invoke2();
        invoke3();
        invoke4();
    }
    //步骤过程:获取字节码->获取方法->方法请求.invoke
    private static void invoke() throws Exception {
        ArrayList list = new ArrayList();

        // 1.class
        Class clazz = list.getClass();

        // 2.method //3.obj
        Method method = clazz.getMethod("add", Object.class);

        // 4.invoke
        method.invoke(list, 132);
        method.invoke(list, "aa");
        method.invoke(list, false);

        System.out.println(list);
        //输出
        //[132, aa, false]
    }
    //一句话一气呵成写法
    private static void invoke2() throws Exception {

        ArrayList list = new ArrayList();

        list.getClass().getMethod("add", Object.class).invoke(list, "good job");
        System.out.println(list);
        //输出
    }   //[goodjob, aa, false]

    /**
     * ͨ注意:需要类名的全称,否则无效
     * Class.forName("java.util.ArrayList")
     * Class.forName("ArrayList")这样虚拟机识别不到该类
     */
    private static void invoke3() throws Exception {
        // Class arrayList = Class.forName("ArrayList");
        Class arrayList = Class.forName("java.util.ArrayList");
        //getDeclaredMethods,获取:公共、保护、默认(包)访问和私有方法,但不包括继承的方法
        Method[] declaredMethods = arrayList.getDeclaredMethods();

        for (Method m : declaredMethods) {
            System.out.println(m);
        }
    }

    /**
     * 获取属性变量
     */
    private static void invoke4() throws Exception {
        Class moon = Class.forName("com.javabase.Moon");  //填写完整类名
        Field[] fields = moon.getDeclaredFields();
        for (Field file :
                fields) {
            System.out.println("-------------"+file);
        }
        //输出:
        //-------------private int com.example.Moon.age
        //-------------private java.lang.String com.example.Moon.name
        //-------------private long com.example.Moon.size
        //-------------public int com.example.Moon.num
        //获取
        Method[] declaredMethods = moon.getDeclaredMethods();

        for (Method m :
                declaredMethods) {
            System.out.println(m);
        //输出:
        //public java.lang.String com.example.Moon.toString()
        //private java.lang.String com.example.Moon.getName()
        //protected long com.example.Moon.getSize()
        //public int com.example.Moon.getAge()
        }
    }

}

包下的类:


    class Moon {
        private int age;
        private String name;
        private long size;
        public int num;

        public int getAge() {
            return age;
        }

        private String getName() {
            return name;
        }

        protected long getSize() {
            return size;
        }

        @Override
        public String toString() {
            return "Moon{" + "age=" + age + ", name='" + name + '\'' + ", size=" + size + '}';
        }
    }

二.JAVA中的静动态代理区别

静态代理 动态代理
只代理一个类 代理一个接口下的多个实现类
知道代理的是什么 不知道代理什么,运行的时候才知道

笔试题:
写一个arrayList的动态代理类:

/**
 * 动态代理实例
 */
public class Invoke_Dynamic {
    public static void main(String[] args) {
        dynimac();
    }

    /**
     * 1.创建一个需求的对象 list
     * 2.通过:代理Proxy.new获取代理实例,得到动态代理对象.
     * 3.内部参数:
     *      1.反射类.获取载入器 loder
     *      2.反射类.获取接口
     *      3.创建"请求处理"接口实例对象,并重写invoke方法
     *          返回:方法对象.使用
     */
    private static void dynimac() {
        final List list = new ArrayList<>();      //1.目标对象
        List  proxy = (List) Proxy.newProxyInstance(         //2.代理.新的代理实例 返回的是集合
                list.getClass().getClassLoader()//3.反射类.载入器
                , list.getClass().getInterfaces()//4.反射类.获取接口
                , new InvocationHandler() {//创建"请求处理"接口实例
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                        return method.invoke(list, args);//返回:方法.请求(目标多少,数组对象)
                    }
                });
        proxy.add(123);
        proxy.add("你好");
        proxy.add(true);
        System.out.println(proxy);
    }
}

输出结果:

[123, 你好, true]

三.JAVA中的设计模式

  • 全部的设计模式(23)种,不必都会,(加粗的为掌握的)
  • 分为三大类:

  • 1.”创建”型模式(5)

工厂方法,抽象工厂,单例,建造者,原型

  • 2.”结构”型模式(7)

适配器,装饰,代理,外观,桥接,组合,享元

  • 3.”创建”型模式(11)

策略,模板方法,观察者,迭代子,责任链,命令,备忘录


为了方便大家的复习和掌握,我特意针对每一种设计模式写了他们对应的一篇介绍,大家可以点击他们各自的连接进行详细的学习:

1.工厂方法模式:分三种(普通,多个,静态)

(点我进入”工厂方法模式”板块的学习)


2.”抽象”工厂方法模式

(点我进入”抽象方法模式”板块的学习)


3.”单例模式

(点我进入”单例模式”板块的学习)


4.”建造者模式”

(点我进入”建造者模式”板块的学习)


5.”适配器模式分三种(类,对象,接口)

(点我进入”适配器模式”板块的学习)


6.装饰模式

(点我进入”装饰模式”板块的学习)


7.策略模式

(点我进入”策略模式”板块的学习)


8.观察者模式

(点我进入”观察者模式”板块的学习)


四.JVM垃圾回收机制和常见算法

1.概念

垃圾回收机制GC(Garbage COllector):

垃圾为什么能回收,肯定经过了发现垃圾的过程再到回收的过程,所以可以说分成两个阶段:搜索和回收阶段.

搜索算法:

  • 1.”引用”“计数器”算法(JDK1.1后不用了)

    1.给"每个对象"设定一个计算器,当被引用时+1,引用失效时-1,为0时,Jvm认为不再被使用,成为了"垃圾".
    2.使用简单,效率高,但是不能解决"循环引用(A引用B,B引用A,AB不被其他对象引用,那么就会累加,所以不符合)"的问题,而且每次都增加和删除开销太大,所以废弃了.
    
  • 2.”根”搜索算法
    1.通过根名为”GC Roots”的对象作为起点,往下搜索
    2.搜索到对象,那么和对象之间的”路径”成为引用链(Reference Chain)
    3.如果那些垂线到GC Roots”没有”引用链,那么该对象就是不可用对象,可回收

    可作为垃圾回收机根的 对象:
    
    1."虚拟机栈"中引用的;
    2.方法区中"静态属性"引用的;
    3.方法区中"常量"引用的
    

    图解:

    谈完了算法的搜索,下面聊回收的过程

回收算法:

  • 1.标记-清除算法

    两个阶段:1.标记;2.清除
    1.标记阶段:标记所要回收的对象
    2.清除阶段紧随其后,删除不可用的标记对象
    是基础的收集算法,单效率不高,易产生大量不连续空间,当程序需要分配大内存时.可能无法找到足够的连续空间(大的需要连续的)
    
  • 2.复制算法

    1.把内存分成等半两边,每次只用一边
    2.垃圾回收时,存活的放另一边,剩下的就是被清理的一块.
    效率高.但是每次只能一办内存,所以内存利用率不高
    
  • 3.标记-整理算法

    在标记-清除算法上升级:
    1.不是逐个删除
    2.而是吧存活的放入内存一端,然后回收"边界以为"的内存
    
  • 4.分代收集
    根据对象”存活时间”分为两种:新生代,老年代

    1.新生代:
        用复制算法.
    2.老年代:
        用标记整理算法.
    

五.谈谈JVM的内存结构和内存分配

一.JAVA内存模型结构

分为3部分:

  • 1.方法区(Method Area)

    常数池,命名的常量,String常量,Static变量都保持在方法区.

  • 2.JAVA”栈”

    java stack 后进先出的特点,一个栈的空间可能是连续也可能不连续
    最典型用法就是方法的调用:虚拟机每调用一次方法就创建一个”方法帧”(frame),退出(完成)方法的时候就”弹出-pop”这个帧.

  • 3.JAVA”堆”

    java head 顺序是随意不确定性的.

二.JAVA内存的分配

  • 1.基础数据类型(字符串不是基础,在data区)-直接在”栈”空间分配;

  • 2.方法的”形式参数”,直接在栈,用完从栈回收

  • 3.方法的”引用参数”,在栈分配地址,比指向堆空间对象区,方法调用完用完从栈回收.

  • 4.引用数据类型(new XXX),栈是地址,堆是类对象具体的

  • 5.局部变量new的,栈堆都分配,声明周期结束,栈立即回收,堆的等回收机制

  • 6.方法调用时的”实际参数”,在栈,用完后从栈释放

  • 7.字符串常量:在data区分配;this在堆(this就是对象)

  • 8.数组:栈分配”数组名”,堆分配实际大小


六.JAVA中引用类型都有哪些?(4类)

(这个是相当重要的,请大家好好理解)

分为四类,从小到大分别为:强->软->弱->虚,很好记.

  • 1.强引用:

    天天敲代码 new的对象就是强引用,当"强引用"对象还使用着,那么垃圾回收器不会"回收"它,即使内存不够的时候,你可抛出内存溢出(OutofMemory)使程序终止,也不回收"强引用"对象
    

java的对象是位于堆head中,堆中的对象有:”强可及”对象,”软可及”对象,弱可及,虚可及,不可及.对象到底属于哪种可及由最强引用决定.

String abc=new String("abc"); //1 
SoftReference<String> softRef=new SoftReference<String>(abc); //2 WeakReference<String> weakRef = new WeakReference<String>(abc); //3  abc=null; //4  
softRef.clear();//5 

第一行,建立abc到该对象的强引用,对象是强可及

第二行,第三行,被分别创建”堆对象”的软,和弱引用,此时”abc对象”已经有了3个引用,此时abc仍是强可及

第四行 abc = null;堆中对象不再是强可及的,变成了软可及

第五行后变成弱可及的了.
* 2.软引用:

1.如果对象只有"软引用",那么如果内存空间还足够,就不会回收它,如果不足,就回收,这是和强不同的第一点
2.配合引用队列ReferenceQueue使用,如果如果软引用对象被回收了,虚拟机会把该软件放入引用队列.
  • 3.弱引用:

    1.弱引用,可有可无,被垃圾回收器扫描到:随时把它干掉
    2.和软引用的区别:比弱引用更低的生命周期,一般发现弱引用,不断内存是否充足都会干掉
    3.也需要一个引用对列RefereneQueue配合,同样一被回收,也会被虚拟机放入引用对列
    
  • 4.虚引用:

    1.形同虚设,不会决定对象的生命周期,如果只持有虚引用,那么如同没有,任何时候都可能被回收,主要用于"跟踪对象被垃圾回收的活动"
    2.也要和引用队列联合使用.当发现垃圾回收器准备回收一个对象,当发现"对象"还有虚引用,就会在回收对象之前,把这个虚引用加入到与之无关联的引用队列
    3.通过判断引用队列中是否加入了虚引用,来了解"被引用的对象"是否要被垃圾回收.
    4.如果某个虚引用已经被加入到队列,那么就可以在所引用的对象在"被回收之前"采取必要行动.
    

七.JAVA的类加载器

1.Java的类加载器的种类有哪些?

  • 1.”根”类加载器

    Bottstrap:C++写的,看不到源码
    
  • 2.”扩展”类加载器

    Extension:加载位置:jre\lib\ext
    
  • 3.”系统(应用)”类加载器

    System/App:加载位置:classpath中
    
  • 4.”自定义”加载器

    必须继承ClassLoader
    

2.类什么时候初始化?

  • 1.创建(new)类时
  • 2.访问”某个类/接口的“静态变量”“,或者对该静态变量”赋值”.
  • 3.调用”某个类的静态方法
  • 4.反射时(Class.forName(“com.lyj.load”)),反射就是要获类中内容,所以当然要创建
  • 5.初始化“一个类的子类”(会首先初始化其父类)
  • 6.JVM启动时标明的启动类,即文件名和类名相同的类

类初始化步骤:

  • 1.如果这个类还没有被加载和链接,那先进行加载和链接
  • 2.如果该类有父类,且该类还没被初始化,那么就初始化直接的父类(不适用接口)
  • 3.加入类中的初始化语句(如:static变量,static块),依次执行这些初始化语句重点内容

你可能感兴趣的