0.说明及目录

1)说明:
整理一些Java基础的笔试面试知识点和题目。
2)问题1~10:

  1. 自定义抛出异常为什么比函数返回结果开销大
  2. 类的初始化顺序
  3. forword请求转发和redirect重定向的区别
  4. 短路运算符和非短路运算符
  5. 访问修饰符的范围(public,private,default,protected)
  6. i++,++i,i=i++及其他i++相关陷阱
  7. String和char[]数组参数传递时的陷阱
  8. try..catch..finally的执行顺序
  9. 字节流和字符流的区别
  10. 上转型对象

2)问题11~20:
-11. 面向对象的三个基本特征
-12. 面向对象五个基本原则
-13. 重写override和重载overload的区别
-14. 什么是面向对象
-15. 关于Java中的关键字
-16. 笔试常见Java命令(非JVM)
-17. Java修饰符整理(访问,非访问,类,接口…)
-18. Java的动态绑定与静态绑定


1.问题1~5

1)自定义抛出异常为什么比函数返回结果开销大?

  1. 函数调用是出栈入栈,栈是除了寄存器速度最快的,而且占用空间很少。
  2. 自定义异常时存放在堆中的,所以自定义抛出异常的开销比较大。

2)类的初始化顺序

  1. 父类中的静态成员变量和静态代码块(按顺序)
  2. 子类的静态成员变量和静态代码块(按顺序)
  3. 父类的普通成员变量和代码块,执行父类构造方法
  4. 子类的普通成员变量和代码块,执行子类构造方法

3)请求转发和重定向的区别?

  1. 请求转发:request.getRequestDispatcher(url).forward(request,response)
    是一种服务器行为,客户端只有一次请求,服务器端转发后会将请求对象保存,地址栏的URL不会改变,得到响应后服务器端再将响应发给客户端。
    保存请求对象后,可以直接在客户端使用保存的request对象。
  2. 请求重定向:response.sendRedirect(url)
    是一种客户端行为,本质上讲是两次请求,前一次的请求对象不会保存。地址栏的URL会变。
    无法在客户端直接使用request对象,需要使用?传值。

4)Java短路运算符合非短路运算符

  1. 短路运算符:
    包括“&&”(逻辑与)和“||”(逻辑或),一般称为条件操作。
    指操作会造成短路,不执行运算符后的操作。如:false&&条件,true||条件。
  2. 非短路运算符:
    包括“&”(与),“|”(或),“^”(异或),一般称为逻辑操作。
    非短路操作会执行运算符前后的表达式,不会造成短路。

5)访问修饰符的范围:

  1. public:公有
    最大公开权限,任何类都能访问,是类的一种对外接口的形式。
  2. protected:子类保护
    只有子类和自己能访问。
  3. default或不加(默认):默认包
    同一个包中的类及自己可以访问。
  4. private:私有
    只有自己能访问,一般成员变量都会设置成私有。

2.问题6~10

6)i++,++i,i=i++及其他i++相关陷阱

  1. i++和++i的区别(简单理解)
    i++:先用后加
    ++i:先加后用
  2. i++和++i的效率问题
    i++:取出i,复制i,增加i,返回副本; (需新建副本)
    ++i:取出i,增加i,返回i;(返回引用)
    所以++i比i++效率更高
  3. i=i++:
    Java中结果=0;
    C/C++中结果=1;
  4. 一道经典题目:
    public class Mutou
    {
        public static void main(String[] args)
        {   
            Mutou test = new Mutou();      
            int i = 0;        
            test.fermin(i);        
            i = i++;             //注意我
            System.out.println(i);    
        }
       void fermin(int i)
       {
            i++;
       }
    }
    
    输出i为0。
    fermin(i)对的参数i是原来的i的副本(i是基本数据类型,参数是按值传递的,会创建一个副本,和i有相同的值),返回值时void,不影响原来的i。
    如果是引用类型传入的副本是地址,会影响原变量的值。
    i=i++值为0,所以结果是0。

7)String和char[]数组参数传递时的陷阱

  1. 笔试题代码:
    public class TestString {
        public void change(String str, char ch[]){
            str="test ok";
            ch[0] = 'g';
        }
        public static void main(String[] args) {
            String str = new String("good");
            char[] ch = {'a','b','c'};
            TestString testString = new TestString();
            //方法处理
            testString.change(str,ch);
            //输出
            System.out.println(str);
            System.out.println(ch);
        }
    }
    
    输出结果:good gbc
  2. 关于参数传递:
    两个参数传递过程中,都是传递了参数指向的内容的地址,不管是基本类型还是引用类型,基本类型只是直接传递变量的值(值副本),而引用类型由于引用的关系,只可以传递一个地址。但是他们对于保存这些信息的变量而言,都是值,传递也是这个值。
    java中不存在引用传递,都是值传递。
  3. Srting和Char[]的区别:
    相同点:固定长度,长度不可变。都是由final修饰的。
    不同点:String的值是不可变的。
  4. 解释:
    String值不可变,长度不变,执行str=”test ok”时会产生一个新对象(不是指向原来的地址),不会影响原来的String对象值。
    char类型的内容是可变的,形参实参都是指向同一个地址,又加上它内容可修改,于是在方法内,可以修改实参的内容。

8)try..catch..finally的执行顺序

  1. 一般情况下,finally中有return语句,try中无异常时,当try执行到return时会执行finally中的代码,其中有return 就直接返回了,忽略try,catch中的return。
  2. 一般情况下,finally中不含return语句,那么当执行到return时,它会被保存等待finally执行完毕后返回,这个时候无论finally内部如何改变这个值(除包装类型和静态变量、全局变量),都不会影响返回结果!如:
    int i = 0 ;
    int test(){
        try {
            return i;
        } catch (Exception e) {
            return -1;
        }finally{
            i++;
        }
    }
    //返回值: 0
    
  3. try中有异常时,catch如果有return,则return前的语句先执行,接着finally的语句,最后是catch的return。如果finally中有return则忽略catch中的return。
    出现异常不执行finally后面的语句。
  4. 如果try,cache中有System.exit(0/1),则不执行finally,也不执行其他代码,直接退出Java程序,关闭虚拟机。
  5. 简单执行顺序总结:
    try–>catch–>finally–>return(遇到exit则直接退出)
  6. 注意事项:
    • finally中避免再次抛出异常,一旦finally中发生异常,代码执行将会抛出finally中的异常信息,try、catch中的异常将被忽略。
    • 在实际项目中,finally常常是用来关闭流或者数据库资源的,并不额外做其他操作。
    • 尽量不要在finally中使用return语句,否则try、catch中的异常将被忽略。

9)字节流和字符流对比

  1. 输出操作时的区别,如图:

    字符流在操作时使用了缓冲区,再通过缓冲区操作文件。
    字节流和字符流的操作完成之后都不关闭输出流,需要手动关闭。
  2. 主要区别:处理方式
    字节流:
    InputStream是所有字节输入流的祖先,而OutputStream是所有字节输出流的祖先。
    字符流:
    Reader是所有读取字符串输入流的祖先,而writer是所有输出字符串的祖先。
    注意:InputStream,OutputStream,Reader,writer都是抽象类。
  3. 字节流的处理:
    字节流是最基本的,所有的InputStream和OutputStream的子类都是,主要用在处理二进制数据,它是按字节来处理的。
  4. 字符流的处理:
    字符流是按虚拟机的Encode来处理,也就是要进行字符集的转化。包括了Reader和Writer的子类。
    字符流和字节流之间通过InputStreamReader,OutputStreamWriter来关联,实际上是通过byte[]和String来关联。
    开发中出现的汉字问题实际上都是在字符流和字节流之间转化不统一而造成的。

10)上转型对象:

  1. 形式
    A是B的父类,形式一:
    A a=new B();
    
    形式二:
    B b=new B();
    A a=b;
    
  2. 编译看左边,运行看右边(下转型也通用)
  3. 上转型对象的特点:
    • 不能操作子类新增的成员变量;不能使用子类新增的方法。
    • 只操作子类的重写的方法,访问子类继承或者隐藏的成员变量。
    • 上转型对象操作子类继承或重写的方法,其作用等价于子类对象去调用这些方法。
    • 如果子类重写了父类的静态方法,那么子类对象的上转型对象不能调用子类重写的静态方法,只能调用父类的静态方法。

3.问题11~15

11)面向对象的三个基本特征

  1. 封装:
    把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
    一个类就是一个封装了数据以及操作这些数据的代码的逻辑实体。
  2. 继承:
    指可以让某个类型的对象获得另一个类型的对象的属性的方法。
    它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。
    实现继承可以通过“继承”(Inheritance)和“组合”(Composition)来实现
    继承概念的实现方式有二类:实现继承与接口继承。实现继承是指直接使用基类的属性和方法而无需额外编码的能力;接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力;
  3. 多态:
    一个类实例的相同方法在不同情形有不同表现形式。

12)面向对象的五大基本原则

  1. 单一职责原则:
    是指一个类的功能要单一,不能包罗万象。
  2. 开闭原则:
    一个模块在扩展性方面应该是开放的而在更改性方面应该是封闭的。
  3. 里氏代换原则:
    子类应当可以替换父类并出现在父类能够出现的任何地方。
  4. 依赖倒转原则:
    高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。
    抽象不应该依赖于具体实现,具体实现应该依赖于抽象。
  5. 接口分离原理:
    模块间要通过抽象接口隔离开,而不是通过具体的类强耦合起来

13)重写和重载的区别:

  1. 重写:override
    • 存在于父类和子类之间,方法名、参数、返回值相同。
    • 子类方法不能缩小父类方法的访问权限。
    • 方法所抛出的异常必须和被重写方法的所抛出的异常一致,或者是其子类;
    • 不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。
    • 重写和多态相关
  2. 重载:overload
    • 方法名相同,参数(参数类型,参数个数,参数顺序)不同
    • 不能重载只有返回值不同的方法名
    • 存在于父类和子类、同类中

14)什么是面向对象?

  1. 面向对象是一种思想,是基于面向过程而言的,就是说面向对象是将功能等通过对象来实现,将功能封装进对象之中,让对象去实现具体的细节;
  2. 这种思想是将数据作为第一位,而方法作为其次,这是对数据一种优化,操作起来更加的方便,简化了过程。

15)关于Java中的关键字

  1. 48个关键字:
    abstract、assert、boolean、break、byte、case、catch、char、class、continue、default、do、double、else、enum、extends、final、finally、float、for、if、implements、import、int、interface、instanceof、long、native、new、package、private、protected、public、return、short、static、strictfp、super、switch、synchronized、this、throw、throws、transient、try、void、volatile、while
  2. 2个保留字(现在没用以后可能用到作为关键字):
    goto、const
  3. 关于true,false和null:
    不是Java的关键字,只是可以直接使用的量(基本单位)

4.问题16~20

16)笔试常见Java命令(非JVM)

  1. javac——编译
    使用:javac XXX.java
    XXX是需要编译的java路径,需要带上后缀.java,将.java文件编译成.class文件。
    注:javac命令跟设置的path环境变量没有关系,设置path环境变量只是为了在任何提示符下都能运行javac,java等命令。
  2. java——执行class文件
    使用:java [-classpath] class文件名(可带路径,不能带后缀)
    关于-classpath环境变量:
    jvm在当前路径中找不到要运行的class文件时,再去classpath指定的路径中继续寻找。
  3. jar——打包命令
    使用:
    jar [c t x u f] [其他参数]  [-C 目录] 文件名(不带后缀)
    c:创建一个jar包
    t:显示jar中的内容列表
    x:解压jar包
    u:添加文件到jar包中
    (这四个参数必须选择一个)
    f:指定jar包的文件名(需要带.jar)
    -C 表示转到相应的目录下执行jar命令,相当于cd到那个目录,然后不带-C执行jar命令
    
  4. javadoc——生成帮助文件
    使用:
    javadoc的使用
  5. javah——生成头文件
    获取Java源文件(.java)并生成C头文件(.h),其中包含您的Java代码中所有本机方法的JNI存根,使Java和C代码可进行交互。
    简单使用:
    javah -jni 文件名(可带路径,不带.java后缀)
  6. javap——反编译
    将.class文件反编译成.java源文件
    使用:javap (带.class后缀)
    具体使用javap -help

17)Java的修饰符(访问,非访问,类,接口…)

  1. 分类:
    Java语言提供了很多修饰符,大概分为两类:
    • 访问权限修饰符
    • 非访问权限修饰符
      具体分类:
    • 访问权限修饰符
    • 非访问权限修饰符
    • 外部类修饰符
    • 内部类修饰符
    • 方法修饰符
    • 成员变量修饰符
    • 接口修饰符
  2. 访问权限修饰符:
    • public:共有访问。对所有的类都可见。
    • protected:保护型访问。对同一个包可见,对不同的包的子类可见。
    • default:默认访问权限。只对同一个包可见,注意对不同的包的子类不可见。
    • private:私有访问。只对同一个类可见,其余都不见。
  3. 非访问权限修饰符:
    • static 修饰符,用来创建类方法和类变量。
    • final 修饰符,用来修饰类、方法和变量,final 修饰的类不能够被继承,修饰的方法不能被继承类重新定义,修饰的变量为常量,是不可修改的。
    • abstract 修饰符,用来创建抽象类和抽象方法。
    • synchronized 用于多线程的同步。
    • volatile 修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值。而且,当成员变量发生变化时,会强制线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
    • transient:序列化的对象包含被 transient 修饰的实例变量时,java 虚拟机(JVM)跳过该特定的变量。
  4. 外部类修饰符:
    • public(访问控制符),将一个类声明为公共类,它可以被任何对象访问,一个程序的主类必须是公共类。
    • default(访问控制符),类只对包内可见,包外不可见。
    • abstract(非访问控制符),将一个类声明为抽象类,抽象类不能用来实例化对象,声明抽象类的唯一目的是为了将来对该类进行扩充,抽象类可以包含抽象方法和非抽象方法。。
    • final(非访问控制符),将一个类生命为最终(即非继承类),表示它不能被其他类继承。
    • 注意
      1. protected和private不能修饰外部类,是因为外部类放在包中,只有两种可能,包可见和包不可见。
      2. final和abstract不能同时修饰外部类,因为该类要么能被继承要么不能被继承,二者只能选其一。
      3. 不能用static修饰类,因为类加载后才会加载静态成员变量。所以不能用static修饰类和接口,因为类还没加载,无法使用static关键字。
  5. 内部类修饰符:
    内部类与成员变量地位一致,所以可以public,protected、default和private,同时还可以用static修饰,表示嵌套内部类,不用实例化外部类,即可调用。
  6. 方法修饰符:
    • public(公共控制符),包外包内都可以调用该方法。
    • protected(保护访问控制符)指定该方法可以被它的类和子类进行访问。
    • default(默认权限),指定该方法只对同包可见,对不同包(含不同包的子类)不可见。
    • private(私有控制符)指定此方法只能有自己类等方法访问,其他的类不能访问(包括子类),非常严格的控制。
    • final ,指定方法已完备,不能再进行继承扩充。
    • static,指定不需要实例化就可以激活的一个方法,即在内存中只有一份,通过类名即可调用。
    • synchronize,同步修饰符,在多个线程中,该修饰符用于在运行前,对它所属的方法加锁,以防止其他线程的访问,运行结束后解锁。
    • native,本地修饰符。指定此方法的方法体是用其他语言在程序外部编写的。
    • abstract ,抽象方法是一种没有任何实现的方法,该方法的的具体实现由子类提供。抽象方法不能被声明成final和static。任何继承抽象类的子类必须实现父类的所有抽象方法,除非该子类也是抽象类。如果一个类包含若干个抽象方法,那么该类必须声明为抽象类。抽象类可以不包含抽象方法。抽象方法的声明以分号结尾,例如:public abstract sample();。
  7. 成员变量修饰符:
    • public(公共访问控制符),指定该变量为公共的,它可以被任何对象的方法访问。
    • protected(保护访问控制符)指定该变量可以别被自己的类和子类访问。在子类中可以覆盖此变量。
    • default(默认权限),指定该变量只对同包可见,对不同包(含不同包的子类)不可见。
    • private(私有访问控制符)指定该变量只允许自己的类的方法访问,其他任何类(包括子类)中的方法均不能访问。
    • final,最终修饰符,指定此变量的值不能变。
    • static(静态修饰符)指定变量被所有对象共享,即所有实例都可以使用该变量。变量属于这个类。
    • transient(过度修饰符)指定该变量是系统保留,暂无特别作用的临时性变量。不持久化。
    • volatile(易失修饰符)指定该变量可以同时被几个线程控制和修改,保证两个不同的线程总是看到某个成员变量的同一个值。
    • final 和 static 经常一起使用来创建常量
  8. 局部变量修饰符:
    无,不能赋予局部变量修饰符。
  9. 接口修饰符:
    • 接口修饰符只能用public、default和abstract。
    • 不能用final、static修饰。
    • 接口默认修饰为abstract。
  10. 接口中方法修饰符:
    • 只能用public abstract修饰,当然如果你什么都不写,默认就是public abstract。
    • 注意:在Java1.8之后,接口允许定义static静态方法了!所以也可以用static来修饰!
  11. 接口中的属性修饰符:
    • 只能是[public] [static] [final]修饰的公开静态常量(默认)

18)Java的动态绑定与静态绑定


最后更新: 2018年09月30日 17:28

原始链接: https://zjxkenshine.github.io/2018/09/28/笔试面试知识点(一)/

× 请我吃糖~
打赏二维码