JAVA学习总结

理论知识

1995年5月23日,Oak语言改名为Java
JAVA之父 詹姆斯.高斯林
JAVA开发语言:
语言:os(载体)+数据结构+算法+思想
思想是语言的灵魂
JAVA --面向对象
C --面向过程
C++ --半面向对象半面向过程

JAVA_HOME:jdk安装目录

CLASSPATH:指定将来要运行加载的class文件所在位置
PATH:java的相关命令所在的文件路径

JDK包含

1.java虚拟机(JVM)
–解释执行JAVA文件
2.JAVA的类库
–java.io.:java.net.
3.java的可执行工具
Javac,java…
bin目录 存放JDK中提供的java相关的命令,例如java、javac、javap等
db目录 JDK自带的一个小型数据库,纯java实现
include目录 JVM启动时需要引入一些C语言的头文件,该目录就是用于存放这些头文件的。
jre目录 JDK自带的一个java运行环境
lib目录 “library”的缩写,目录中提供了一些Java类库和库文件,也就是jar包。
src.zip文件 压缩文件,目录存放JDK核心类的源代码,也就是JavaSE-API的源代码

java语言的优点:

1.提供一个解释性环境
加速开发、一次编写/编译,到处运行,代码可以跨平台、多线程、支持动态更新
2.提供比较简单的语言
1.取消指针,程序级别取消,底层存在,但是程序员不关心
2.没有内存管理
程序员手动开辟内存 new 一个
不关心内存的回收

GC:垃圾回收器

C:malloc()开辟空间,free()释放空间
C++:new开辟,delete()释放空间
Java:new开辟,gc释放空间
垃圾:无用的对象内存

Gc:什么时候回收
1.内存不够用
2.系统闲置时
标记清扫法
不会整理内存,会产生碎片
效率高,节约时间
内存搬移法
会整理内存,不会产生碎片
效率低,浪费时间

GC:垃圾回收机制

java代码中,开辟要使用的内存空间,使用new关键字即可完成。
垃圾回收是一种自动的存储管理机制。 当一些被占用的内存不再需要时,就应该予以释放,以让出空间,这种存储资源管理,称为垃圾回收(Garbage Collection)。 垃圾回收器可以让程序员减轻许多负担,也减少程序员犯错的机会。

什么时候?

GC触发的条件有两种: (1)程序调用System.gc时可以触发; (2)系统自身来决定GC触发的时机。

程序计数器:线程私有。是一块较小的内存,是当前线程所执行的字节码的行号指示器。是Java虚拟机规范中唯一没有规定OOM(OutOfMemoryError)的区域。

Java栈:线程私有。生命周期和线程相同。是Java方法执行的内存模型。执行每个方法都会创建一个栈帧,用于存储局部变量和操作数(对象引用)。局部变量所需要的内存空间大小在编译期间完成分配。所以栈帧的大小不会改变。存在两种异常情况:若线程请求深度大于栈的深度,抛StackOverflowError。若栈在动态扩展时无法请求足够内存,抛OOM。

Java堆:所有线程共享。虚拟机启动时创建。存放对象实力和数组。所占内存最大。分为新生代(Young区),老年代(Old区)。新生代分Eden区(特点:朝生夕死),Survior区。Survior区又分为From space区和To Space区。Eden区和Survior区的内存比为8:1。 当扩展内存大于可用内存,抛OOM。
默认挺过15次迭代会被放在老年代
(1)新生代:所有新 new 出来的对象都会最先出现在新生代中,当新生代这部分内存满了之后,就会发起一次垃圾收集事件,这种发生在新生代的垃圾收集称为 Minor collections。 这种收集通常比较快,因为新生代的大部分对象都是需要回收的,那些暂时无法回收的就会被移动到老年代。全局暂停事件(Stop the World):所有小收集(minor garbage collections)都是全局暂停事件,也就是意味着所有的应用线程都需要停止,直到垃圾回收的操作全部完成。
(2)老年代:老年代用来存储那些存活时间较长的对象。 一般来说,我们会给新生代的对象限定一个存活的时间,当达到这个时间还没有被收集的时候就会被移动到老年代中。随着时间的推移,老年代也会被填满,最终导致老年代也要进行垃圾回收。这个事件叫做大收集(major garbage collection)。大收集也是全局暂停事件。通常大收集比较慢,因为它涉及到所有的存活对象。所以,对于对相应时间要求高的应用,应该将大收集最小化。此外,对于大收集,全局暂停事件的暂停时长会受到用于老年代的垃圾回收器的影响。

方法区:所有线程共享。用于存储已被虚拟机加载的类信息、常量、静态变量等数据。又称为非堆(Non – Heap)。方法区又称“永久代”。GC很少在这个区域进行,但不代表不会回收。这个区域回收目标主要是针对常量池的回收和对类型的卸载。当内存申请大于实际可用内存,抛OOM。
(3)永久代(JDK1.8后叫做源空间):永久代存储了描述应用程序类和方法的源数据,JVM 运行应用程序的时候需要这些源数据。 永久代由 JVM 在运行时基于应用程序所使用的类产生。 此外,Java SE 类库的类和方法可能也存储在这里。如果 JVM 发现有些类不在被其他类所需要,同时其他类需要更多的空间,这时候这些类可能就会被垃圾回收。

本地方法栈:线程私有。与Java栈类似,但是不是为Java方法(字节码)服务,而是为本地非Java方法服务。也会抛StackOverflowError和OOM。

对什么东西?

自动垃圾回收机制就是寻找Java堆中的对象,并对对象进行分类判别,寻找出正在使用的对象和已经不会使用的对象,然后把那些不会使用的对象从堆上清除。
那那些会使用和不会使用的对象是什么呢?换句java语言就是,当一个对象没有被引用指向的时候就说明它就是不会使用的对象了。怎么判断它到底有没有被引用指向呢?两种方式:引用计数法、可达性分析

做了怎么样的处理

垃圾回收算法。它总共有四种类型:
( 1 )标记-清除算法
a.标记,也就是垃圾收集器会找出那些需要回收的对象所在的内存和不需要回收的对象所在的内存,并把它们标记出来,简单的说,也就是先找出垃圾在哪儿?
2 )复制算法
标记清除算法每次执行都需要对堆中全部对象扫面一遍效率不高,为解决效率问题,复制算法将内存按容量划分为大小相等的两块,每次只是用其中的一块。 当这一块使用完了,就将还存活的对象复制到另一块上面,然后再把已使用过的内存空间一次清理掉。 这样使得每次都对半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。紧接着它的缺点就来了会减少可用内存。
3 )标记-整理算法
由于简单的标记清除可能会存在碎片的问题,所以又出现了压缩清除的方法,也就是先清除需要回收的对象,然后再对内存进行压缩操作,将内存分成可用和不可用两大部分。
4 )分代收集算法
分代算法是上面几个算法的综合, Java 堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。 在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。 而老年代中因为对象存活率较高、没有额外的空间对它进行分配担保,就必须使用“标记-清除”或者“标记-整理”算法来回收。

类加载器:

加载:查找并加载类的二进制文件(class文件),将其置于内存中

字节码验证者

检验class类的完整性(语法结构是否正确,和其他类的协调是否一致)
提高累的程序的健壮性,确保程序能够正常执行

验证内容

1.代码和jvm定义规范是否一致,语法和版本的兼容性
2.不能破坏系统完整性
3.没有堆栈的上溢和下溢
4.参数类型正确
5.类型转换是否正确

Java语法

1.编译成class文件 javac -d . Hello.java
2.运行java java com.briup.day01.Hello

生成的包不要进去编译

  1. Package:定义包名

    1.使用层级样式管理类CLASS,最终以目录形式展示
    2.避免命名冲突
    3.改变类的名字
    包名+类名 权限命名
    4.报名的命名规则
    公司域名的倒写,功能
    公司域名的倒写.组名,功能

  2. import
       		引入其他包的内容
       	
       	Date日期类,由java.util.Date 引入
       	
       	对应是权限类名
       	
       	java.lang包的内容不需要导入
    
  3. public class公有类名 名字必须和文件名保持一致
  4. class定义类

    public 修饰符 公共的 公有的

  5. 一个java文件中可以有多个类,但是只能有1个公有类

    方法

public static void main(String[] args){}

main是程序的主入口

定义方法的基本结构

修饰符 返回值类型 方法名 (参数列表){//String[] args或者String args[]

//方法体,业务功能

}

public 公有的 static 静态的 不使用static修饰的方法就是非静态方法

void 代表没有返回值

有返回值 写对应的返回值类型 需要结合return关键词 return后面跟上返回的数据

静态方法可以直接被静态方法调用,不能直接调用非静态方法

new 对象调用 new Hello().eat();

System.out.println(Object类型);

多个点连用要知道每一个点

后面被调用的内容是点前面所对应的返回对象第调用

javac -d . Hello.java

命令中,-d表示编译时自动生成和包名对应的目录结构(class存放路径),-d后面的点(.)表示就在当前目录中生成
注意,编译成功后,还会自动把编译好的class文件存到这个生成的目录中

Hello是我们自己定义的一个类,为什么写java代码的时候要写一个类?

因为在java中,类是组织代码的基本的单元,在类中,可以编写方法,在方法里面,才是真正需要JVM去
执行的一行行的代码,我们平时所说的代码执行,就是这的这些方法中的代码。
java语言中规定,在大多数情况下,需要把执行的代码写在方法中,方法写到类中,所以在写代码的时
候,一般都是先定义一个类,类中定义一个方法,然后把要执行的代码写到方法
那么这里所说的类中和方法中,具体的表现形式,就是一对花括号{},如果这对花括号是属于类的,那
么括号里面就表示类中,如果这对花括号属于方法的,那么括号里面就表示方法中。

public class Student{
//这里是就是类中
}
//--------------------
public class Student{
public void run(){
//这里就是方法中,当然这个方法整体也在类中
}
}

在Hello中,我们为什么可以使用System这个类?
  1. System这个类所在的.java文件已经编写完成,并且已经编译成.class文件

    ​ System.java文件在src.zip中,编译好的System.class文件在rt.jar中

  2. 这个.class文件所在位置,是JVM可以自动加载的指定路径,这样就可以保证JVM可以把这个.class
    文件中的字节码(也就是System这个类的代码),加载到JVM的内存中
    JVM在启动的时候,会自动读取rt.jar中所需要的class文件,当然也包括System.class文件

  3. 在Hello中,使用import(导入)关键字,将要使用的System类,引入到Hello中,如果System类是
    在java.lang包中进行定义的,或者System类和Hello类是在同一个包下面定义的,那么import语句
    可以省去不写

当前Hello类中,是没有声明package(包)的,那么这时候Hello类就算是在默认包中,而System
类,是在java.lang包下定义的,所以当前情况下, Hello类中不使用import导入,也可以直接使用
System类

Java对引用的概念进行了扩充

将引用分为强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)四种,这四种引用强度依次逐渐减弱。

javadoc -author -version -d doc *.java

控制台常用指令

javac
编译命令
java
运行命令
javadoc
生成API文档命令
javap
反解析命令,可以解析出class字节码文件的内容
jar
打包命令

注释

类、方法上面用多行注释

变量及代码用单行注释

说明某段代码的作用,或者说明某个类的用途、某个属性的含义、某个方法的功能,方法参数和返回值的数据类型、意义

注释可以增强代码的可读性,让自己或者他人快速的理解代码含义和设计思路,同时可以便于后期的对
系统中代码的维护和迭代升级等。
Java源码代码中的注释,不会出现在字节码文件中,因为在编译的时候,编译器会忽略掉源代码中的注
释部分。因此,可以在源代码中根据需要添加任意多的注释,而不必担心字节码文件会膨胀。

单行注释

最常用的注释方式,其注释内容从 "//"开始到本行末尾。

多行注释

注释从 “/" 开始,到 "/” 结束。
它可以注释一行,也可以注释多行

文档注释

可以注释单行,也可以注释多行,以 “/**” 开始,以 "*/"结束的。
同时在Java中,文档注释也被用于生成API文档

分号

java中,一句代码都是以分号(;) 来结束的。
需要使用分号的代码语句有:
包的声明语句
类的引入语句
属性的声明语句
方法中要执行的代码

java中进行解析执行代码的时候,就是根据代码后面的分号来确定是一句代码还是俩句代码;

标识符
命名规则

标示符可以由字母、数字、下划线_ 、美元符号$组成
标示符开头不能是数字
标识符中的字符大小写敏感
标识符的长度没有限制
标示符不能使用java中的关键字或保留字

推荐规则–驼峰命名法

类和接口,首字母大写,如果是俩个单词,第二个单词的首字母大写
例如,public class Account{} ,public interface AccountBase{}
方法和变量,首字母小写,如果是俩个单词,第二个单词的首字母大写
例如,public void getStudentName(){} , int personNum = 1;
常量,全部字母大写,如果是俩个单词,使用下划线分隔
例如,public static final int MAX_NUM = 10;
尽量使用有意义的名字,尽量做到见名知义。
例如,int numOfStudnet = 10; String userName = “tom”;

关键字

赋予特殊含义的名词
保留字:当前未使用,后面可能被使用的名词
标识符
自定义的名字 不能以数字开头,不能用关键字作为标识符

变量的定义:

内存中的一个存储空间,存放数据不确定的数据
变量空间的开辟需要什么要素呢?
1,这个空间要存储什么数据?数据类型。
2,这个空间叫什么名字啊?变量名称。
3,这个空间的第一次的数据是什么? 变量的初始化值。

数据类型:

数据类型决定了接受什么数据

变量名是赋予该类型接受的数据意义

1):基本数据类型:

整数类型:byte、short、int、long

浮点类型:float、double

字符类型:char

布尔类型:boolean

char类型占2个字节(16位),用来表示字符,是基本数据类型,String表示字符串,是类类型。一
个String是由0~n个char组成

2):引用数据类型: 数组、类、接口。

1.基本数据类型的值是不可变的(我们不能给基本数据类型添加属性和方法);
2、基本数据类型的比较是值的比较(只有他们的值相等的时候才是相等的);
3、基本数据类型的变量是存放在栈里面的

引用数据类型:

1、引用数据类型可以拥有属性和方法,且值是可变的;
2、引用数据类型的值是同时保存在栈内存和堆内存的对象

引用数据类型作为函数参数的时候。在方法里面修改了这个数据的属性值的时候,相应的也会跟着在改变,因为引用数据类型传的是自身的地址,如果你修改了它里面的属性值,它对应的属性值也会跟着改变。

基本数据类型是分配在栈上的,而引用类型是分配在堆上的

类型转换
1.强制类型转换,精度高到低,超出数据范围

byte a =(byte)129

级别从低到高为:byte<short<int<long<float<double
自动类型转换:从低级别到高级别,系统自动转的;
强制类型转换:什么情况下使用?把一个高级别的数赋给一个别该数的级别低的变量;

2.隐式转换:精度低的转精度高的,或者在精度低的范围内

参与运算时

​ 变量对应的高精度和低精度参与运算结果为高精度的

精度问题

浮点型
float和double都是java中的浮点型,浮点型可以用来表示小数,它们的二进制表示方式和整型不同
float是32位, 1符号位+8指数位+23尾数位
double是64位 1符号位+11指数位+52尾数位
float和double的精度是由尾数的位数来决定的。浮点数在内存中是按科学计数法来存储的.
float的精度为7位左右有效数字
double的精度为16位左右有效数字

理解对象

分析事物–》定义类–》声明属性/方法/构造器–》编写main方法–》创建对象–》使用对象访问属
性、调用方法 --》完成功能

java是最接近人的自然思维方式

类:将具有相同属性和行为抽取的模板

对象 类的具体化,通过new操作

运行时数据在低层区域怎么划分?

方法区:存放类的信息

栈区:存放变量或者值

堆区:保存值

常量池:保存常量

PC寄存器:指令

new操作怎么分配

1.先在栈区开辟空间保存对象引用

2.在堆区开辟空间保存对象

3.将堆区的地址值赋值给栈区的对象引用。引用:地址

变量属性

why?有变量和数据类型

​ 处理程序的实质-----处理数据------处理变量

变量之间的数据传递

数据类型 – 变量名–给个含义说明该变量名中需要存放哪类数据

**变量的作用:

​ 程序中使用变量可以接收、保存、传递、操作数据

​ 变量的类型和数据的类型必须是一致的

​ 如果类型不一致,那么就需要进行类型转换(自动转换、手动转换)
变量的使用:

​ 必须是先声明、再赋值、再使用

​ 也可以声明变量的同时就进行赋值,然后再使用

​ 如果只声明变量,没有赋值,那么再使用的时候会报错
变量的种类:

通过类型划分
基本类型变量(byte short int long float double char boolean)
引用类型变量(类类型、接口类型、数组类型)

通过范围划分
局部变量

先声明、再赋值、再使用

位置:方法的参数列表和方法体

作用域:从定义的地方到方法的结束有效

生命周期:从定义的地方到方法的结束结束

​ 实例变量

先声明、再赋值、再使用

位置:类下面,方法外面

作用域:在整个类中有效

生命周期:从对象开始创建的时候 GC回收结束

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U2IBZ85d-1628598011236)(D:\QQ下载\new堆栈图.png)]

常量池还是地址判断

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jyMFQV7N-1628598011240)(D:\QQ下载\String堆栈图.png)]

赋值运算

a+=b 等价于a=(左边的数据类型)(a+b) a+b会自动隐式转换

移位运算符

<<(左移)

无符号左移,最低位补0

如果移动的位数超过了该类型的最大位数,那么编译器会对移动的位数取模/取余。如果对int
型移动33位,实际上只移动了33%32=1位。如果对int型移动32位,实际上只移动了32%32=0位

10<<2

0000… 0010 1000

(带符号右移)>>

最高位补符号位

对于负数的右移:因为负数在内存中是以补码形式存在的,所有首先根据负数的原码求出负数的补码(符号位不变,其余位按照原码取反加1),然后保证符号位不变,其余位向右移动到X位,在移动的过程中,高位补1.等移位完成以后,然后保持符号位不变,其余按位取反加1,得到移位后所对应数的原码 *

10>>2 2

0000…1010 有符号右移2位 0000…0010

-10>>2 ==-3

1000…1010 取反 1111…0101 取补 1111…0110

右移 1111…1101

减一取反 :减一 1111…1100 取反1000…0011

或者取反加1:取反1000…0010 加一 1000…0011

得到原码1000…0011

(无符号右移)

不保留最高位符号位,最高位始终补 0

注意,这个操作的本质就是除以2^n
,这个n就是我们右移的位数
注意,除以2^n之后,只保留整数部分
注意,正数和负数右移之后,最左边空出的位置,都要补0
例如:
12>>>1 结果是 6
-12>>>1 结果是 2147483642
注意:在操作的时候,java操作的都是计算机中的补码

12 1100 ->0110

-12 >>>1

-12 原码 1000 1100 反码 1111 0011 补码 1111 0100 右移一位 高位补0

01111…1010

位运算符

~取反运算

正数取反为负数 所以需要对补码进行减一取反,在按位取反获得原码

负数取反为整数 获得负数补码进行取反就是要得到的原码

-5 100…0101
111…1010
补码 111…1011
~-5补码 000…0100//最高位为0 正反补一直
10 补码0…1010
~10补码 1…0101//最高位为1 正反补不同
反码 1…0100
原码 10…1011

正数的原码、反码、补码都是一样的
例如:数字1的原码0000 0001,反码0000 0001,补码0000 0001
负数的原码、反码、补码有所不同
例如:数字-1
原码:1000 0001
反码:1111 1110 除了符号位之外,其他按位取反
补码:1111 1111 反码基础上加1

逻辑运算

逻辑与:
有0出0,全1出1
逻辑或:
有1出1,全0出0
逻辑非:
相反

逻辑运算符
& | ^ ! && ||
逻辑运算符除了 ! 外都是用于连接两个 boolean 类型表达式。
&: 只有两边都为 true 结果是 true。否则就是 false。
|:只要两边都为 false 结果是 false,否则就是 true
^:异或:和或有点不一样。
两边结果一样,就为 false。0
两边结果不一样,就为 true.1
& 和 &&区别: & :无论左边结果是什么,右边都参与运算。
&&:短路与,如果左边为 false,那么右边不参数与运算。
| 和|| 区别:|:两边都运算。
||:短路或,如果左边为 true,那么右边不参与运算。

判断语句:满足条件才能执行的语句

1.单分支语句

if(条件){

}

2.双分支语句

if(条件){

}else{

}

3.多分支语句

if(条件){

}else if{

}else if{

}else{

}

循环嵌套
for循环
while循环
do…while 循环

区别在于:如果需要定义变量控制循环次数。建议使用 for。因为 for 循环完毕,变量在内存中释

Random

生成随机数

生成一个【200,500】的整数

int a=(int)Math.random()*(最大数-最小数+1)+最小数;
int b=new Random().nextInt(301)+200;
函数其实就是一个功能,定义函数就是实现功能,通过两个明确来完成:

1)、明确该功能的运算完的结果,其实是在明确这个函数的返回值类型。
2)、在实现该功能的过程中是否有未知内容参与了运算,其实就是在明确这个函数的参
数列表(参数类型&参数个数)。
函数的作用:
1)、用于定义功能。
2)、用于封装代码提高代码的复用性。
注意:函数中只能调用函数,不能定义函数

重载的定义是:在一个类中,如果出现了两个或者两个以上的同名函数,只要它们的参数的个
数,或者参数的类型不同,即可称之为该函数重载了。
如何区分重载:当函数同名时,只看参数列表。和返回值类型没关系。

如何在 java 中表现一个数组呢?两种表现形式。

1)、元素类型[] 变量名 = new 元素类型[元素的个数];
2)、元素类型[] 变量名 = {元素 1,元素 2…};
元素类型[] 变量名 = new 元素类型[]{元素 1,元素 2…};

Equals与==的区别

== 的作用:
  基本类型:比较的值是否相同(四类八种基本数据类型,byte,short,char,int,long,float,double,boolean。String不是基本数据类型)
equals 的作用:
  引用类型:默认情况下,比较的是地址值。
1、基本类型之间的比较一般是用==,但是注意float和double类型的精度问题以及NaN、正无穷大、负无穷大、-0.0、0.0的比较问题
2、引用类型的比较一般是用equal,尤其是字符串,因为==是指对象地址之间的比较,而对象地址之间的比较一般是无意义的。

Continue与break的区别

break:作用于 switch ,和循环语句,用于跳出,或者称为结束。
break 语句单独存在时,下面不要定义其他语句,因为执行不到,编译会失败。当循环嵌套时,break 只跳出当前所在循环。

continue:只作用于循环结构,继续循环用的。
作用:结束本次循环,继续下次循环。该语句单独存在时,下面不可以定义语句,执行不到。

如果想让break或continue针对某一个指定的循环起作用,那么可以使用label标签给循环起名字,然后使
用break或continue加上循环的名字即可。

test1:for(int i=0;i<3;i++){//外层循环
test2:for(int j=0;j<5;j++){//内层循环
if(j==2){
break test1;
}
System.out.println(“i=”+i+",j="+j);
}
System.out.println("----------------------");
}

continue:结束本次循环,还可以继续后面的循环

break:用break语句可以使流程跳出switch语句体,也可以用break语句在循环结构终止本层循环体,从而提前结束本层循环

数组

含义:保存一组具有相同数据类型元素的有序集合

元素:数组中的每一个数据

集合:保存多个数据

有序:根据元素位置获取元素

​ 根据下标方式:下标取值范围:0-总长-1

使用数据

1.声明数据

​ 基本数据类型数组

​ int[] array;

​ int array[];

​ 引用数据类型数组

​ Student[] array;

​ String[] array;

​ Student array[];

2.数组的创建和赋值

​ int[] array;

​ array=new int[5];//数组长度

​ array[0]=20;

​ array[1]=30;

  1. int[] arr = new int[5];
    创建数组对象,没有还没有给其赋值
  2. int[] arr = new int[]{1,3,5,7,9};
    创建数组对象的同时,并赋值
  3. int[] arr = {1,3,5,7,9};
    java提供了创建数组对象的简便形式
  4. int[] arr;
    arr = new int[]{1,3,5,7,9};
    显示声明数组类型变量,然后创建对象,并赋值

面试专栏:

个人认为讲的很好的链接:https://www.baidu.com/link?url=C-QbXbePsgTdwLt1DAJLsetpl18H0kW3Xo7lfx7YL27iYL0lyV_2oJ-WIasW0H9etm6OFbtOhMkZU_Ofw_ZSu_&wd=&eqid=d6c9050a000271dc00000004610904dc

深拷贝和浅拷贝

基本数据类型是赋值的数据,所以不存在拷贝行为

对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。因为是两份不同的数据,所以对其中一个对象的该成员变量值进行修改,不会影响另一个对象拷贝得到的数据。

基本数据类型是值传递,所以修改值后不会影响另一个对象的该属性值;

引用数据类型是地址传递(引用传递),所以修改值后另一个对象的该属性值会同步被修改。

String类型非常特殊。首先,String类型属于引用数据类型,不属于基本数据类型,但是String类型的数据是存放在常量池中的,也就是无法修改的!

拷贝就是赋值

深拷贝和浅拷贝最根本的区别在于是否真正获取一个对象的复制实体,而不是引用。

假设B复制了A,修改A的时候,看B是否发生变化:

如果B跟着也变了,说明是浅拷贝,拿人手短!(修改堆内存中的同一个值)

如果B没有改变,说明是深拷贝,自食其力!(修改堆内存中的不同的值)

看的是B与A是否重新开辟一个内存空间存放所有数据。 如果存在一个相同的内存空间存放数据则认为是浅拷贝 //简单理解

img

img

浅拷贝(shallowCopy)只是增加了一个指针指向已存在的内存地址,

深拷贝(deepCopy)是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存,

使用深拷贝的情况下,释放内存的时候不会因为出现浅拷贝时释放同一个内存的错误。

浅复制:仅仅是指向被复制的内存地址,如果原地址发生改变,那么浅复制出来的对象也会相应的改变。

深复制:在计算机中开辟一块新的内存地址用于存放复制的对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
XMind是一款功能强大的思维导图软件,可以帮助开发者更好地组织和管理自己的学习进程。对于Java开发学习来说,XMind可以扮演着重要的角色。 首先,XMind可以用来制定学习计划。在学习Java开发的过程中,我们需要系统地学习各个方面的知识,包括语法、面向对象思想、数据结构等等。使用XMind,我们可以将这些知识点以树状结构组织起来,清晰地列出每个知识点的内容,规划好学习的先后顺序。这样一来,我们就可以明确自己需要学习的内容,并制定相应的学习计划。 其次,XMind还可以用来整理学习笔记。在学习过程中,我们难免会遇到各种各样的问题和知识点。使用XMind,我们可以将这些问题和知识点整理成思维导图,清晰地呈现出与学习相关的核心概念和关系。这样一来,我们可以更好地理解和掌握学习内容,并在需要的时候轻松地找到相关的知识点。 另外,XMind还可以用来复习和总结学习成果。随着学习的进行,我们掌握的知识点越来越多。使用XMind,我们可以将已经学习过的知识点整理成思维导图,复习和回顾学习过程中的重要内容。这样一来,我们可以巩固已经掌握的知识,并发现可能存在的问题和不足。 总之,XMind可以作为学习Java开发的有效工具,有助于规划学习进程、整理学习笔记、复习和总结学习成果。通过合理地使用XMind,我们可以更高效地学习Java开发,并在实践中不断提升自己的技能水平。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值