• 面试题—JAVA基础9.19/20


    目录

    try-catch

    总结:

    局部变量和实例变量

     final

    问:JDBC为什么是桥接模式?

    多线程

    串池

     static

    Cookie

    从哪能获取cookie值?

    Cookie和Session 

    四大作用域 

    内部类

     修饰符

    对String和作用域的思考

    super()和this()

    溢出


     

    try-catch

    当Java程序中执行try-catch时遇到了retrun语句或者throw语句,会导致立即结束——>如果有finally的话,只有当finally块执行完结束后,再回来执行try-catch中的return;如果finally中也有return的话,那么finally执行完后就不会再返回try-catch中的return了

    例题2

     

    答案:1201 

    总结:

    1、不管有木有出现异常,finally块中代码都会执行;

    2、当try和catch中有return时,finally仍然会执行;
    3、finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是在finally执行前确定的;
    4、finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。
    举例:

    情况1:try{} catch(){}finally{} return;

    显然程序按顺序执行。

    情况2:try{ return; }catch(){} finally{} return;

    程序执行try块中return之前(包括return语句中的表达式运算)代码;
    再执行finally块,最后执行try中return;
    finally块之后的语句return,因为程序在try中已经return所以不再执行。

    情况3:try{ } catch(){return;} finally{} return;

    程序先执行try,如果遇到异常执行catch块,
    有异常:则执行catch中return之前(包括return语句中的表达式运算)代码,再执行finally语句中全部代码,
    最后执行catch块中return. finally之后也就是4处的代码不再执行。
    无异常:执行完try再finally再return.

    情况4:try{ return; }catch(){} finally{return;}

    程序执行try块中return之前(包括return语句中的表达式运算)代码;
    再执行finally块,因为finally块中有return所以提前退出。

    情况5:try{} catch(){return;}finally{return;}

    程序执行catch块中return之前(包括return语句中的表达式运算)代码;
    再执行finally块,因为finally块中有return所以提前退出。

    情况6:try{ return;}catch(){return;} finally{return;}

    程序执行try块中return之前(包括return语句中的表达式运算)代码;
    有异常:执行catch块中return之前(包括return语句中的表达式运算)代码;
    则再执行finally块,因为finally块中有return所以提前退出。
    无异常:则再执行finally块,因为finally块中有return所以提前退出。
    最终结论:任何执行try 或者catch中的return语句之前,都会先执行finally语句,如果finally存在的话。
    如果finally中有return语句,那么程序就return了,所以finally中的return是一定会被return的,

    编译器把finally中的return实现为一个warning。

    局部变量和实例变量

     实例变量:就是我们的全局变量,它是默认初始化的,有默认值

     局部变量:形参这种,必须要初始化

     final

    1.final修饰的方法,方法是不能重写的——>但是可以重载

    2.final修饰的类不可继承,所以接口,抽象类这些是不能final修饰的也没什么意义

     桥接模式

    问:JDBC为什么是桥接模式?

    前景:这跟它的设计有关,我们不同数据库传输协议那些都不同,也就是Driver不同——>那么我们难道Java要为每一种数据库都要写一个接口去支持数据库厂商的实现吗?

    那肯定不行,所以用到了桥接模式

    1. try {
    2. Class.forName("com.mysql.jdbc.Driver");
    3. String url = "";
    4. String user = "";
    5. String password = "";
    6. Connection con = DriverManager.getConnection(url, user, password);
    7. } catch (Exception e) {
    8. }

    像我们正常的话就是继承实现,但是你每多一个数据库,子类就会成指数型增长——>用组合的方式实现

    比如我们这里的JDBC——>这里Java做的是提供一套接口让厂商自己实现,一套接口给程序开发者调用,两者的结合就是经典的桥接模式

    这里写图片描述

     DriverManager是个Driver容器(连接),管理不同的Driver,每次执行Class.forName()的时候,大家可以看到有一块静态static 代码,执行了具体Driver向DriverManager注册注入的过程:这样具体的数据Driver实现就统一交给容器管理,执行验证连接,获取连接的操作

    1. public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    2. // Register ourselves with the DriverManager
    3. //
    4. static {
    5. try {
    6. java.sql.DriverManager.registerDriver(new Driver());
    7. } catch (SQLException E) {
    8. throw new RuntimeException("Can't register driver!");
    9. }
    10. }

    例子:

    我们前面这些conn连接就是面向用户,DriverManager就是连接,后面的api就是面向数据库厂商

    1. public class jdbcTest {
    2. public static void main(String[] args) {
    3. try {
    4. //加载数据库驱动jar包
    5. ///mysql8版本:com.mysql.cj.jdbc.Driver
    6. Class.forName("com.mysql.jdbc.Driver");
    7. } catch (ClassNotFoundException e) {
    8. e.printStackTrace();
    9. }
    10. //第一个参数:数据库连接
    11. //第二个参数:用户名
    12. //第三个参数:密码
    13. String url="jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8";
    14. try {
    15. //获取数据库链接对象
    16. Connection connection=DriverManager.getConnection(url,"root","root");
    17. System.out.println("连接成功"+ connection);
    18. //获取执行sql语句的对象
    19. Statement statement=connection.createStatement();
    20. // 增加
    21. // String sql="insert into student values(null,'张三',19,'男',now())";
    22. // 修改
    23. // String sql="update student set name='李四',age=22 where stuid=1";
    24. // 删除
    25. // String sql="delete from student where stuid=1";
    26. // 增删改都要用这个方法,
    27. // statement.executeUpdate(sql);
    28. // System.out.println("修改成功");
    29. // 查询
    30. String sqll="select * from student";
    31. // 查询得到的结果集
    32. ResultSet resultSet = statement.executeQuery(sqll);
    33. System.out.println();
    34. while (resultSet.next()){
    35. // columnlabel:通过字段名称查询
    36. // columnindex:通过字段位置查询
    37. System.out.print(resultSet.getInt(1)+"\t");
    38. System.out.print(resultSet.getString("name")+"\t");
    39. System.out.print(resultSet.getInt(3)+"\t");
    40. System.out.println(resultSet.getString("sex")+"\t");
    41. System.out.println(resultSet.getInt(5));
    42. }
    43. } catch (SQLException throwables) {
    44. throwables.printStackTrace();
    45. }
    46. }
    47. }

    多线程

     

    每个线程一定是先打印0-4,最后再打印空格,所以说空格的出现代表前面一定有0-4的出现,所以选c 

    串池

    一般都是问new Strng("abc")创建几个对象这种,我统一来说说

    String s="abc": 通过字面量赋值创建字符串。则将栈中的引用直接指向该字符串,如不存在——>则在常量池中生成一个字符串,再将栈中的引用指向该字符串(创建0-1个对象)

    String s="a"+"bc": 编译阶段会直接将“a”和“bc”结合成“abc”,这时如果方法区已存在“abc”,则将s的引用指向该字符串,如不存在,则在方法区中生成字符串“abc”对象,然后再将s的引用指向该字符串

    String s="a"+new String("bc"): 像new的话会先在串池中看有没有,没有就在串池中来一个对象,然后再在堆中创建一个,并且引用指向堆中的——>(创建1-2个对象)
    String s = "a" + new String("bc"):栈中先创建一个"a"字符串常量,再创建一个"bc"字符串常量,编译阶段不会进行拼接,在运行阶段拼接成"abc"字符串常量并将s的引用指向它,效果相当于String s = new String("abc"),只有'+'两边都是字符串常量才会在编译阶段优化

     

     static

    1.类名直接访问,不能this调用——>this和super不能一起用,都是掉父类会引起资源浪费现象,并且必须第一行

    2.静态代码块在类加载时指向一次

    3.实例对象时可以调用静态方法的

    1. package com.wyh.SE.lc.Test;
    2. public class test01 {
    3. public static void test(){
    4. System.out.println("11");
    5. }
    6. public static void main(String[] args) {
    7. test01 t = new test01();
    8. t.test();
    9. }
    10. }

    从哪能获取cookie值?

     request.getParameter()取得是通过容器的实现来取得通过类似post,get等方式传入的数据(参数),request.setAttribute()和getAttribute()只是在web容器内部流转,仅仅是请求处理阶段(请求域)

    两个WEB间为转发关系时,转发目的WEB可以用getAttribute()方法来和转发源WEB共享request范围内的数据

    Cookie和Session 

    (38条消息) 从Http思考项目中的cookie和session+ServletContext_Fairy要carry的博客-CSDN博客

    四大作用域 

    (38条消息) 从Http思考项目中的cookie和session+ServletContext_Fairy要carry的博客-CSDN博客

    (38条消息) 什么是会话_墨时澈℡的博客-CSDN博客_会话 

    内部类

     成员内部类:可以访问外部所有资源,本身自己就是要依靠外部类进行实例化——>所以自己里面是不能有static属性的

     局部内部类:只能访问final变量和形参,因为一般在外部类的一般方法中

     匿名内部类:创建的时候一般跟个new,没有类名构造器,所以是没有static资源,毕竟连类名都没有

    另外我们非静态内部类是可以访问外部类所有权限字段的,通过invokestatic执行外部类的static方法access得到外部类对象构造方法

    ——>所以说我们静态内部类不依靠外部类存在,得不到外部类的引用

    然后还有些内存泄漏的情况也要注意,static字段为root引用回收不了,然后注意非静态内部类持有外部类引用如果没有被

    (39条消息) Java基础面试题_Fairy要carry的博客-CSDN博客

     修饰符

    default: 指默认权限,也叫包访问权限,只能在包中访问

    public:公开访问,所有地方

    protected:可以在其他包中访问,但前提是有继承关系。。

    private:只能在当前类中访问

    对String和作用域的思考

    1. package com.wyh.SE.lc.Test;
    2. public class Example{
    3. String str=new String("tarena");
    4. char[]ch={'a','b','c'};
    5. public static void main(String args[]){
    6. Example ex=new Example();
    7. ex.change(ex.str,ex.ch);
    8. System.out.print(ex.str+" and ");
    9. System.out.print(ex.ch);
    10. }
    11. public void change(String str,char ch[]){
    12. //引用类型变量,传递的是地址,属于引用传递。
    13. str="test ok";
    14. ch[0]='g';
    15. }
    16. }

    问结果是多少?

    解决:字符串的实例存在在串池中(锁定了资源不被篡改),是不可变的,而代码上str的指向只是在change方法中发生了改变,所以说出了change方法,结果就变了;而char数组是会改变原值的,资源并没有被锁定

    super()和this()

    super()必须在第一行的原因是: 子类是有可能访问父类对象的, 比如在构造函数中使用父类对象的成员函数和变量, 在成员初始化使用了父类, 在代码块中使用了父类等等, 所以为保证在子类可以访问父类对象之前,一定要完成对父类对象的初始化(第一行默认super())。   关于this()必须在第一行的原因,我们假设这样一种情况,,类B是类A的子类, 如果this()可以在构造函数的任意行使用, 那么当程序运行到构造函数B()的第一行,发现没有调用this()和super(),那么就会自动在第一行补齐super() 来完成对父类对象的初始化, 然后返回子类的构造函数继续执行, 当运行到构造函数B()的"this() ;"时, 调用B类对象的构造函数, 还会对父类对象再次初始化!,这就造成了资源的浪费,以及某些意想不到的错误。也正因如此C选项错误。

    D选项,无论是this()还是super()指的都是对象,而static环境中是无法使用非静态变量的。因此D选项错误

    溢出

     

    java中只有byte, boolean是一个字节, char是两个字节, 所以对于java来说127不会发生溢出, 输出328

    boolean也可能占四个字节,因为JVM识别不了boolean,编译后会用int来代替——>一字节8位,byte1位,int4位,所以boolean也可能四位

    如果boolean是单独使用:boolean占4个字节——>boolean在底层实际会调用int,那么既然int占4个字节,boolean也自然占4个字节。即,boolean类型占4个字节

    如果boolean是以“boolean数组”的形式使用:boolean占1个字节——>boolean数组在底层会用到byte指令,那么既然byte占1个字节,boolean数组中的boolean也就占1个字节。即,boolean数组中的boolean占1个字节

    但是对于c/c++语言来说, char是一个字节, 会发生溢出, 对127加一发生溢出,  0111 1111 --> 1000 0000, 1000 0000为补码-128, 所以结果为200-128=72

  • 相关阅读:
    java计算机毕业设计汉服配饰销售系统源码+mysql数据库+系统+LW文档+部署
    JAVA 基础与进阶系列索引 -- JAVA 进阶系列
    javaSE学习笔记(四)常见类,基本数据类型包装类,StringBuffer&StringBuilder
    小红书笔记发布最佳时间为几点?几点发布更容易上热门?
    半导体动态杂谈
    Hadoop 之文件读取
    动态规划(背包常见问题)
    Linux rpm命令详解
    光环云出席Enjoy出海AIGC主题研讨会,助力企业迎接AI时代机遇与挑战
    磁盘相关概述
  • 原文地址:https://blog.csdn.net/weixin_57128596/article/details/126953127