值传递
当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,这个过程属于值传递还是引用传递?
是值传递。
Java 语言的方法调用只支持参数的值传递
。
当一个对象作为参数在方法中被传递时,传递的实际上是该对象的引用。在方法执行期间,对象内部的属性可以发生变化,但传入方法的对象引用本身并不会改变,也不会影响到调用方法的外部环境。然而引用的本质也是一个值,所以为值传递。
为什么 Java 中只有值传递 ?
首先回顾一下在程序设计语言中有关将参数传递给方法(或函数)的一些专业术语。按值调用(call by value)表示方法
接收的是调用者提供的值,而按引用调用(call by reference)表示方法接收的是调用者提供的变量地址。一个方法可
以修改
传递引用所对应的变量值
,而不能修改
传递值调用所对应的变量值。
Java程序设计语言总是采用按值调用。方法得到的总是参数值的拷贝,也就是说,方法不能修改传递给它的任何参数变量的内容。
下面通过 3 个例子来给大家说明:
example1:
public static void main(String[] args){
int num1 =10;
int num2 =20;
swap(num1, num2);
System.out.println("num1 = "+ num1);
System.out.println("num2 = "+ num2);
}
public static void swap(int a,int b){
int temp = a;
a = b;
b = temp;
System.out.println("a = "+ a);
System.out.println("b = "+ b);
}
结果:
a =20;b =10;num1 =10;num2 =20;
解析:
在swap方法中,a、b的值进行交换,并不会影响到 num1、num2。因为,a、b中的值,只是从 num1、num2 的复制过来的。也就是说,a、b相当于num1、num2 的副本,副本的内容无论怎么修改,都不会影响到原件本身。
通过上面例子,我们已经知道了一个方法不能修改一个基本数据类型的参数,而对象引用作为参数就不一样,请看:
example2:
public static void main(String[] args){
int[] arr ={1,2,3,4,5};
System.out.println(arr[0]);
change(arr);
System.out.println(arr[0]);
}
public static void change(int[] array){
// 将数组的第一个元素变为0
array[0]=0;
}
结果:
10
解析:
array 被初始化 arr 的拷贝也就是一个对象的引用,也就是说 array 和 arr 指向的时同一个数组对象。 因此,外部对引用对象的改变会反映到所对应的对象上。
通过 example2 我们已经看到,实现一个改变对象参数状态的方法并不是一件难事。理由很简单,方法得到的是对象引用的拷贝,对象引用及其他的拷贝同时引用同一个对象。
很多程序设计语言(特别是,C++和Pascal)提供了两种参数传递的方式:值调用和引用调用。有些程序员认为Java程序设计语言对对象采用的是引用调用,实际上,这种理解是不对的。由于这种误解具有一定的普遍性,所以下面给出一个反例来详细地阐述一下这个问题:
example3:
public class Test{
public static void main(String[] args){
Student s1 = new Student("小张");
Student s2 = new Student("小李");
Test.swap(s1, s2);
System.out.println("s1:"+ s1.getName());
System.out.println("s2:"+ s2.getName());
}
public static void swap(Student x, Student y){
Student temp = x;
x = y;
y = temp;
System.out.println("x:"+ x.getName());
System.out.println("y:"+ y.getName());
}
}
结果:
x:小李 y:小张 s1:小张 s2:小李
解析:
交换之前:
交换之后:
通过上面两张图可以很清晰的看出: 方法并没有改变存储在变量 s1 和 s2 中的对象引用。swap方法的参数x和y被初始化为两个对象引用的拷贝,这个方法交换的是这两个拷贝。
总结
Java程序设计语言对对象采用的不是引用调用,实际上,对象引用是按值传递的。
Java中方法参数的使用情况:
一个方法不能修改一个基本数据类型的参数(即数值型或布尔型)
一个方法可以改变一个对象参数的状态。
一个方法不能让对象参数引用一个新的对象。
值传递和引用传递有什么区别?
值传递:指在方法调用时,传递的参数是按值的拷贝传递,传递的是值的拷贝,也就是说传递后原数据和拷贝后的数据之间并没有直接的引用关系,它们在内存中是独立的。
引用传递:指在方法调用时,传递的参数是按引用进行传递,其实传递的是引用的地址,也就是变量所对应的内存空间的地址。传递的是值的引用,也就是说传递前和传递后都指向同一个引用(也就是同一个内存空间)。
Java包
JDK 中常用的包有哪些?
java.lang:系统基础类;
java.io:所有输入输出有关的类,比如文件操作等;
java.nio:为了完善 io 包中的功能,提高 io 包中性能而写的一个新包;
java.net:与网络有关的类;
java.util:系统辅助类,特别是集合类;
java.sql:这数据库操作的类。
import java和javax有什么区别?
Java API 在初始阶段,必要的包是以 "java" 开头的,而 "javax" 仅仅是作为扩展 API 包来使用。然而,随着时间的发展,"javax" 逐渐扩展并成为了 Java API 的一部分。尽管如此,将扩展部分从 "javax" 包转移到 "java" 包会非常繁琐,并且可能会破坏大量现有的代码。因此,为了保持现有代码的稳定性,决定将 "javax" 包加入 Java API 的标准部分。
所以目前看来,二者只是类库名称不同,都是Java API的标准库,没有本质上的区别。
IO流
java 中 IO 流分为几种?
按照流的流向分,可以分为输入流和输出流;
按照操作单元划分,可以划分为字节流和字符流;
按照流的角色划分为节点流和处理流。
Java Io流共涉及40多个类,这些类看上去很杂乱,但实际上很有规则,而且彼此之间存在非常紧密的联系, Java I0流的40多个类都是从如下4个抽象类基类中派生出来的:
InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。
按操作方式分类结构图:
按操作对象分类结构图:
BIO,NIO,AIO 有什么区别?
简答:
BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。
NIO:Non IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。
AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制。
详细回答:
BIO (Blocking I/O):
同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成。在活动连接数不是特别高(小于单机1000)的情况下,这种模型是比较不错的,可以让每一个连接专注于自己的 I/O 并且编程模型简单,也不用过多考虑系统的过载、限流等问题。线程池本身就是一个天然的漏斗,可以缓冲一些系统处理不了的连接或请求。但是,当面对十万甚至百万级连接的时候,传统的 BIO 模型是无能为力的。因此,我们需要一种更高效的 I/O 处理模型来应对更高的并发量。
NIO (New I/O):
NIO是一种同步非阻塞的I/O模型,在Java 1.4 中引入了NIO框架,对应 java.nio 包,提供了 Channel , Selector,Buffer等抽象。
NIO中的N可以理解为Non-blocking(即非阻塞),不单纯是New。
它是面向缓冲的,基于通道的I/O操作方法。NIO提供了与传统BIO模型中的
Socket
和
ServerSocket
相对应的
SocketChannel
和
ServerSocketChannel
两种不同的套接字通道实现,两种通道都支持阻塞和非阻塞两种模式。阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性都不好;非阻塞模式正好与之相反。对于低负载、低并发的应用程序,可以使用同步阻塞I/O来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发。
AIO (Asynchronous I/O):
AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改进版 NIO 2,它是异步非阻塞的IO模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。AIO 是异步IO的缩写,虽然 NIO 在网络操作中,提供了非阻塞的方法,但是 NIO 的 IO 行为还是同步的。对于 NIO 来说,业务线程是在 IO 操作准备好时,得到通知,接着就由这个线程自行进行 IO 操作,IO操作本身是同步的。
加餐小tips:
如何理解上文中:“NIO中的N可以理解为Non-blocking(即非阻塞),不单纯是New”呢?
“N”在NIO中代表的是“Non-blocking”,强调了它的非阻塞特性。这也是NIO与传统IO操作最大的不同点:NIO的选择器允许一个线程管理多个通道,实现了I/O操作的多路复用。所以,一个线程可以监控多个通道的状态,而当某个通道准备好执行I/O操作时,线程可以立即进行处理,其他通道则在后台继续准备。
NIO模型的引入改善了Java在处理大量并发I/O请求时的性能,减少了线程的阻塞,提高了资源利用率,并能够更好地支持高并发处理。
NIO模型的引入改善了Java在处理大量并发I/O请求时的性能,减少了线程的阻塞,提高了资源利用率,并能够更好地支持高并发处理。
Files的常用方法都有哪些?
Files. exists():检测文件路径是否存在。
Files. createFile():创建文件。
Files. createDirectory():创建文件夹。
Files. delete():删除一个文件或目录。
Files. copy():复制文件。
Files. move():移动文件。
Files. size():查看文件个数。
Files. read():读取文件。
Files. write():写入文件。