目录
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修饰的也没什么意义
桥接模式
前景:这跟它的设计有关,我们不同数据库传输协议那些都不同,也就是Driver不同——>那么我们难道Java要为每一种数据库都要写一个接口去支持数据库厂商的实现吗?
那肯定不行,所以用到了桥接模式
- try {
- Class.forName("com.mysql.jdbc.Driver");
- String url = "";
- String user = "";
- String password = "";
- Connection con = DriverManager.getConnection(url, user, password);
- } catch (Exception e) {
-
- }
像我们正常的话就是继承实现,但是你每多一个数据库,子类就会成指数型增长——>用组合的方式实现
比如我们这里的JDBC——>这里Java做的是提供一套接口让厂商自己实现,一套接口给程序开发者调用,两者的结合就是经典的桥接模式
DriverManager是个Driver容器(连接),管理不同的Driver,每次执行Class.forName()的时候,大家可以看到有一块静态static 代码,执行了具体Driver向DriverManager注册注入的过程:这样具体的数据Driver实现就统一交给容器管理,执行验证连接,获取连接的操作
- public class Driver extends NonRegisteringDriver implements java.sql.Driver {
-
- // Register ourselves with the DriverManager
- //
- static {
- try {
- java.sql.DriverManager.registerDriver(new Driver());
- } catch (SQLException E) {
- throw new RuntimeException("Can't register driver!");
- }
- }
例子:
我们前面这些conn连接就是面向用户,DriverManager就是连接,后面的api就是面向数据库厂商
- public class jdbcTest {
- public static void main(String[] args) {
- try {
- //加载数据库驱动jar包
- ///mysql8版本:com.mysql.cj.jdbc.Driver
- Class.forName("com.mysql.jdbc.Driver");
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- }
- //第一个参数:数据库连接
- //第二个参数:用户名
- //第三个参数:密码
- String url="jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8";
- try {
- //获取数据库链接对象
- Connection connection=DriverManager.getConnection(url,"root","root");
- System.out.println("连接成功"+ connection);
- //获取执行sql语句的对象
- Statement statement=connection.createStatement();
- // 增加
- // String sql="insert into student values(null,'张三',19,'男',now())";
- // 修改
- // String sql="update student set name='李四',age=22 where stuid=1";
- // 删除
- // String sql="delete from student where stuid=1";
- // 增删改都要用这个方法,
- // statement.executeUpdate(sql);
- // System.out.println("修改成功");
- // 查询
- String sqll="select * from student";
- // 查询得到的结果集
- ResultSet resultSet = statement.executeQuery(sqll);
- System.out.println();
- while (resultSet.next()){
- // columnlabel:通过字段名称查询
- // columnindex:通过字段位置查询
- System.out.print(resultSet.getInt(1)+"\t");
- System.out.print(resultSet.getString("name")+"\t");
- System.out.print(resultSet.getInt(3)+"\t");
- System.out.println(resultSet.getString("sex")+"\t");
- System.out.println(resultSet.getInt(5));
- }
- } catch (SQLException throwables) {
- throwables.printStackTrace();
- }
- }
- }
多线程
每个线程一定是先打印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.实例对象时可以调用静态方法的
- package com.wyh.SE.lc.Test;
-
- public class test01 {
- public static void test(){
- System.out.println("11");
- }
- public static void main(String[] args) {
- test01 t = new test01();
- t.test();
- }
- }
Cookie
request.getParameter()取得是通过容器的实现来取得通过类似post,get等方式传入的数据(参数),request.setAttribute()和getAttribute()只是在web容器内部流转,仅仅是请求处理阶段(请求域)。
两个WEB间为转发关系时,转发目的WEB可以用getAttribute()方法来和转发源WEB共享request范围内的数据
(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和作用域的思考
- package com.wyh.SE.lc.Test;
-
- public class Example{
- String str=new String("tarena");
- char[]ch={'a','b','c'};
- public static void main(String args[]){
- Example ex=new Example();
- ex.change(ex.str,ex.ch);
- System.out.print(ex.str+" and ");
- System.out.print(ex.ch);
- }
- public void change(String str,char ch[]){
- //引用类型变量,传递的是地址,属于引用传递。
- str="test ok";
- ch[0]='g';
- }
- }
问结果是多少?
解决:字符串的实例存在在串池中(锁定了资源不被篡改),是不可变的,而代码上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