基础知识专题整理-----持续更新
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;
}
}
}
- 最后return动作是由finally代码块中的return ++z完成的,所以方法返回的结果是101。
- 语句return ++x中的++x被成功的执行,所以运行结果是x=2。
- 如果有异常抛出,那么运行结果将会是y=11,而x=1。
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
}
}