当前位置: 首页 > news >正文

基础知识专题整理-----持续更新

Java基础

一:java值传递与引用传递

值传递:

值传递是指在方法调用时,传递的是实际参数的一个副本。无论在方法内部对这个副本如何修改,都不会影响到方法外部的实际参数,这种方式常用于传递基本数据类型,(int,float,boolean等)

值传递的特点

方法接受的是参数的一个副本,而不是参数本身

方法内部对参数的修改不会影响到方法外部的实际参数。

引用传递:

引用传递是指在方法调用时,传递的是参数的引用(内存地址),因此方法接收到的是实际参数的引用,任何对引用的修改都会直接影响到实际参数。这种方式常用于传递对象和数组。

然而,java中,不存在真正的引用传递,java总是以值传递的方式进行参数传递,但对于对象而言,传递的是对象引用的副本,由于引用的副本指向的是同一个对象,因此方法内部的修改会影响到外部对象的状态。 

Java中参数传递的实际机制


Java中的参数传递机制被称为“值传递”。具体来说:

基本数据类型:当传递基本数据类型时,传递的是值的副本。因此,方法内部对参数的修改不会影响外部变量。
对象:当传递对象时,传递的是对象引用的副本。由于引用副本指向同一个对象,因此方法内部对对象的修改会影响外部的对象。

基本数据类型的值传递

public class Test {
    public static void main(String[] args) {
        int num = 10;
        modifyPrimitive(num);
        System.out.println("Value of num after method call: " + num);  // 输出: 10
    }

    static void modifyPrimitive(int x) {
        x = 20;  // 修改副本,不影响原始变量
    }
}

对象引用的值传递

public class Test {
    public static void main(String[] args) {
        Person person = new Person("Alice");
        modifyObject(person);
        System.out.println("Name after method call: " + person.getName());  // 输出: Bob
    }

    static void modifyObject(Person p) {
        p.setName("Bob");  // 修改对象属性,影响外部对象
    }
}

修改对象引用本身的副本

public class Test {
    public static void main(String[] args) {
        Person person = new Person("Alice");
        modifyReference(person);
        System.out.println("Name after method call: " + person.getName());  // 输出: Alice
    }

    static void modifyReference(Person p) {
        p = new Person("Charlie");  // 修改引用本身,不影响外部的引用
    }
}

二、Static静态代码块

案例一:

public class Person {

    // 静态代码块:在类加载时候执行静态代码块,只会执行一次
    static {
        System.out.println("Person.static initializer");  
    }

    // 实例初始化块,每次调用构造方法之前首先调用实例初始化块
    {
        System.out.println("Person.instance initializer");
    }

    public Person() {
        System.out.println("Person.Person");
    }
}

public void test1() {
    Person person1 = new Person();
    Person person2 = new Person();
}

Person.static initializer

Person.instance initializer

Person.Person

Person.instance initializer

Person.Person

案例二:

public class Test{
    static int cnt = 6;
    static{
        cnt += 9;
    }

    public static void main(String[] args){
        System.out.println(“cnt =” + cnt);
    }

    static{
        cnt /= 3;
    };
}

cnt的值是 A

A、cnt=5

B、cnt=2

C、cnt=3

D、cnt=6

静态初始化块,静态变量这两个是属于同一级别的,是按代码写得顺序执行的!

public class StaticDemo{  
   static {
      cnt = 6;
   }
   static int cnt = 100;
   public static void main(String[] args) {
      System.out.println("cnt = " + cnt);
      // 最后输出是50,
      // 按顺序执行就是cnt=6--->cnt=100---->cnt = 100/2 = 50.
   }
   static {
      cnt /= 2;
   }
}

问题:为什么cnt变量的声明放在了后面不报错?JVM加载流程

执行静态变量、静态代码块之前,首先扫描类里面所有的静态变量赋值为默认值cnt=0;

静态初始化块,静态变量赋值这两个是属于同一级别的,是按代码写得顺序执行的!

案例三

(1)父类静态成员和静态初始化块,按在代码中出现的顺序依次执行。 clinit

(2)子类静态成员和静态初始化块,按在代码中出现的顺序依次执行。 clinit

(3)父类实例成员和实例初始化块,按在代码中出现的顺序依次执行。 init

(4)执行父类构造方法。init

(5)子类实例成员和实例初始化块,按在代码中出现的顺序依次执行。init

(6)执行子类构造方法。init

public class Person {
    private static User1 user1 = new User1();
    private User2 user2 = new User2();

    // 静态代码块:在类加载时候执行静态代码块,只会执行一次
    static {
        System.out.println("Person.static initializer");
    }

    // 实例初始化块,每次调用构造方法之前首先调用实例初始化块
    {
        System.out.println("Person.instance initializer");
    }

    public Person() {
        System.out.println("Person.Person");
    }
}

public class Student extends Person{
    private static User3 user3 = new User3();
    private  User4 user4 = new User4();

    static {
        System.out.println("Student.static initializer");
    }

    {
        System.out.println("Student.instance initializer");
    }

    public Student() {
        super();
        System.out.println("Student.Student");
    }
}

User1.User1

Person.static initializer

User3.User3

Student.static initializer

User2.User2

Person.instance initializer

Person.Person

User4.User4

Student.instance initializer

Student.Student

三、finally代码块

必须执行的代码块,不管是否发生异常,即使发生outofmemoryerror也会执行,通常用于执行善后处理工作。

   

 如果finally代码块没有执行,那么有三种情况:

 1:没有进入try代码块

2:进入try代码块,但是代码运行中出现了死循环或者死锁的情况。

3:进入try代码块,但是执行了System.exit()操作。

注意,finally代码块是在return表达式运行后执行的,此时return的结果已经暂存起来,待finally代码块执行结束后再将之前暂存的结果返回。

public static void main(String[] args) {
    int result = finallyNotWork();
    System.out.println(result);// 10001
}
public static int finallyNotWork() {
    int temp = 10000; 
    try {
        throw new Exception();
    } catch (Exception e) {
        return ++temp;
    } finally {
        temp = 99990;
    }
}

finally代码块的职责不在于对变量进行赋值等操作,而是清理资源、释放连接、关闭管道流等操作。

相对在finally代码块中赋值,更加危险的做法是在finally块中使用return操作,这样的代码会使返回值变得非常不可控,警示代码如下:

public class TryCatchFinally {
  static int x = 1;
  static int y = 10;
  static int z = 100;
  
  public static void main(String[] args) {
    int value = finallyReturn();
    System.out.println("value=" + value);
    
    System.out.println("x=" + x);
    System.out.println("y=" + y);
    System.out.println("z=" + z);
  }
  private static int finallyReturn() {
    try {
       // ...
       return ++x;
    } catch (Exception e) {
       return ++y;
    } finally {
       return ++z;
    }
  }
}
执行结果如下:
value=101
x=2
y=10
z=101
以上执行结果说明:
  1. 最后return动作是由finally代码块中的return ++z完成的,所以方法返回的结果是101。
  2. 语句return ++x中的++x被成功的执行,所以运行结果是x=2。
  3. 如果有异常抛出,那么运行结果将会是y=11,而x=1。
finally代码块中使用return语句,使返回值的判断变得复杂,所以避免返回值不可控,我们不要在finally代码块中使用return语句。
Class Test{
    public static String output="";

    public static void foo(int i){
        try{
            if(i==1){
                throw new Exception();
            }
            output+="1";
        } catch(Exception e){
            output+="2";
            return;
        }  finally{
            output+="3";
        }
        output+="4";
    }
    public static void main(String args[]){
        foo(0);
        System.out.println(output);//134
        foo(1);
        System.out.println(output);//13423
    }
}

 

相关文章:

  • lib-zo,C语言另一个协程库,整理
  • leetcode0704. 二分查找-easy
  • 关于labview中路径的问题
  • 一款功能强大的手机使用情况监控工具
  • 探访 DINO 家族 Part 4:融合多模态大语言模型的视觉模型基础 RexSeek
  • 【计算机网络】记录一次校园网无法上网的解决方法
  • Android 地区选择器或者其他选择器
  • 【蓝桥杯14天冲刺课题单】Day 1
  • 指针函数、函数指针和指针函数指针的全面总结
  • MySQL表缺乏主键或唯一索引对主从复制的深度影响及解决方案
  • linux课程学习三——静态/动态库的创建
  • 使用无人机进行露天矿运输道路分析
  • js中三元表达式(条件运算符)的用法总结
  • VCP考试通过率低?
  • vs2022中使用spdlog、C++日志
  • 时序数据库 InfluxDB(五)
  • 文件分享系统--开源的可视化文件共享管理工具
  • LeetCode 438. 找到字符串中所有字母的异位词
  • 9、tlm 事务交互通信
  • 【11408学习记录】破译语言密码·征服数学迷宫——长难句拆解与方程不等式全析
  • 数字展厅网站建设/沈阳seo排名优化推广
  • 学做烤制食品的网站/网络营销方案案例
  • 关于优化网站建设的方案/百度热搜的含义
  • 做内贸的有哪些网站/网上国网app推广
  • 重庆ssc做号网站/百度推广方案
  • wordpress主题the7.6/网站排名优化服务