• Java面试01


    一、谈谈你对java的理解

    1、平台无关性,一次编译到处运行

    2、GC

    3、语言特性

    4、面向对象

    5、类库

    6、异常处理

    二、Java如何做到一次编译到处运行?(如何做到平台无关性)

    首先我们先来编写一个java程序:

    public class ByteCodeSimple {
        public static void main(String[] args) {
            int i = 1, j = 5;
            i++;
            ++j;
            System.out.println(i);
            System.out.println(j);
        }
    }

    首先我们先对这段程序使用javac 命令进行编译:

    可以看到得到了对应ByteCodeSimple.class

    之后再src目录下,用java命令加上包名执行class文件,我们可以看到他的执行是符合预期的。

    我们如何查看.class文件呢,可以通过Idea打开,就可以自动进行反编译。

    下面我们使用javap命令来进行反编译-c的意义代表反编译,如果想查询帮助指令,可以输入javap -help进行查询。

    一次编译到处运行如何实现?

    java文件->.class文件

    Java源码首先被编译成字节码,再由不同平台的JVM进行解析,Java语言在不同的平台上运行时不需要重新进行编译,Java虚拟机在执行字节码时,把字节码转换成具体平台的机器指令。

    三、JVM如何加载.class文件

    JVM最值得学习:jvm内存模型,GC

    Class Loader(类加载器):依据特定格式,加载class文件到内存

    Execution Engine(执行引擎):对命令进行解析。

    Native Interface(本地方法借口):融合不同开发语言的原生库为Java所用。

    Runtime Data Area(内存模型):JVM内存空间结构模型。

    结论:首先是由ClassLoader加载.class文件,之后通过Execution Engine命令进行执行。

    四、什么是反射?

    首先新建一个Robot类

    public class Robot {
        private String name;
    
        public void hello1(String content) {
            System.out.println(content + name);
        }
    
        private String hello2(String content) {
            return "hello2" + content + name;
        }
    }

    使用反射去调用Robot类中的方法:

    public class ReflectSample {
        public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
            //根据类名获取Class对象
            Class rc = Class.forName("com.interview.reflect.Robot");
            //根据类类型,去创建Robot对象
            Robot robot = (Robot) rc.newInstance();
            //调用方法hello1
            robot.hello1("123");
    
            //这个方法可以获得道类内部的所有方法包含公有和私有方法,却不能获得器父类继承的方法,和接口实现的方法
            Method method = rc.getDeclaredMethod("hello2", String.class);
            //在反射私有方法时要设置这个方法的值为true
            method.setAccessible(true);
            //执行方法并获得返回值
            String result = (String) method.invoke(robot, "wzy");
            //输出结果
            System.out.println("result:" + result);
    
            //这个方法可以获取类内的公有方法,和父类继承公有的方法;
            Method method1 = rc.getMethod("hello1", String.class);
            //调用方法hello1
            method1.invoke(robot, "welcome");
    
            //获取私有成员变量
            Field name = rc.getDeclaredField("name");
            //设置允许方法私有属性
            name.setAccessible(true);
            //设置私有对象的值
            name.set(robot, "yuan");
    
            //调用hello1方法
            method1.invoke(robot, "123");
        }
    }

    运行结果:

    五、谈谈ClassLoader

    类从编译到执行的过程

    编译器将Robot.java源文件编译为Robot.class字节码文件

    ClassLoader将字节码转换为JVM中的Class<Robot>对象

    JVM利用Class<Robot>对象实例化为Robot对象。

    ClassLoader在Java中有着非常重要的作用,它主要工作在Class的装载的加载阶段,其主要作用是从系统外部获得Class的二进制数据流,它是Java的核心组件,所有的

    Class都是由ClassLoader进行加载的,ClassLoader负责通过将Class文件里的二进制数据流装载进系统,让后交给java虚拟机进行连接、初始化等操作。

    通过查看源码我们可以发现,ClassLoader是一个抽象类:

    其中最重要的方法就是ClassLoader中的loadClass(String name)方法

    我们还可以发现ClassLoader类当中有parent成员变量,是另一个ClassLoader说名ClassLoader的种类不止一种。

    ClassLoader的种类:

    BootStrapClassLoader:C++编写,加载核心库java.*

    ExtClassLoader:Java编写,加载扩展库javax.*(用户看的到的ClassLoader)(C:Javajdkjrelibext;C:WindowsSunJavalibext)

    AppClassLoader:Java编写,加载程序所在的目录

    自定义ClassLoader:Java编写,定制加载

    通过查看ExtClassLoader源码,可以看到它的class的加载路径,用到才会去加载

     我们对这个路径进行打印得到:

    通过查看AppClassLoader源码,我们可以看到其对应的加载路径:

    对这个路径进行打印,得到结果,其中就包含了我们项目本身的.class文件输出路径out.加载类路径(classpath)最重要的路径:E:projectjavabasicoutproductionjavabasic;

    实现自定义ClassLoader:

    首先我们先创建一个类:

    1 public class Wali {
    2     static {
    3         System.out.println("Hello Wali");
    4     }
    5 }

    之后单独对这个类使用javac进行编译,而不通过IDE,注意这个Wali类中没有定义package,否则执行的时候需要带着包名

    创建一个MyClassLoader类

     1 public class MyClassLoader extends ClassLoader {
     2     /**
     3      * 加载类的路径
     4      */
     5     private String path;
     6     /**
     7      * 类加载器的名称
     8      */
     9     private String classLoaderName;
    10 
    11     /**
    12      * 定义构造方法
    13      * @param path 加载类的路径
    14      * @param classLoaderName 类加载器的名称
    15      */
    16     public MyClassLoader(String path, String classLoaderName) {
    17         this.path = path;
    18         this.classLoaderName = classLoaderName;
    19     }
    20 
    21     /**
    22      * 用于寻找类文件
    23      * @param name
    24      * @return
    25      */
    26     @Override
    27     public Class findClass(String name) {
    28         byte[] b = loadClassData(name);
    29         return defineClass(name, b, 0, b.length );
    30     }
    31 
    32     /**
    33      * 将文件转换为字节流
    34      * @param name
    35      * @return
    36      */
    37     private byte[] loadClassData(String name) {
    38         //拼接出文件的名字
    39         name = path + "\" + name + ".class";
    40         InputStream in = null;
    41         ByteArrayOutputStream bos = null;
    42 
    43         try {
    44             in = new FileInputStream(name);
    45             bos = new ByteArrayOutputStream();
    46             int i = 0;
    47             //对文件进行读取
    48             while ((i = in.read()) != -1) {
    49                 bos.write(i);
    50             }
    51         } catch (IOException e) {
    52             e.printStackTrace();
    53         } finally {
    54             try {
    55                 in.close();
    56                 bos.close();
    57             } catch (IOException e) {
    58                 e.printStackTrace();
    59             }
    60         }
    61         //返回字节数组
    62         return bos.toByteArray();
    63     }
    64 }

    MyClassLoader测试类:

    1 public class MyClassLoaderChecker {
    2     public static void main(String[] args) throws IllegalAccessException, InstantiationException {
    3         MyClassLoader myClassLoader = new MyClassLoader("E:\project\javabasic\src\com\interview\reflect", "myClassLoader");
    4         Class aClass = myClassLoader.findClass("Wali");
    5         //创建对象触发执行静态块代码
    6         Object o = aClass.newInstance();
    7     }
    8 }

    运行结果:

  • 相关阅读:
    实时获取管道信息的一个小框架
    multiprocessing还是threading?
    QThread的一些使用心得
    super超类继承特点小结
    打靶总结
    简析Colorspace
    第一个Unity3D脚本
    一个新的计划,写在年末
    lambda函数的特性
    Nuke Python module的使用
  • 原文地址:https://www.cnblogs.com/fengyun2019/p/11223457.html
Copyright © 2020-2023  润新知