Java_note

认识java

JDK8
JDK1.8

JDK5
JDK

java(JDK)–1995
sun公司 --被收购–》 oracle公司

mysql

java se

java ee

java me

java 编程语言

API文档

基础的代码

调用 —》已经写好的代码
而不是重新发明轮子

java 定位:后台服务器端的编程语言

java se   工具 API   桌面应用开发    C/S架构
核心java(corejava)

java ee   工具 API   企业级应用开发  B/S架构

java me   工具 API   移动设备开发    手机应用

系统 32位 64位

安装

步骤

路径 路径中不要出现中文

C:\Program Files\Java\jdk1.8.0_74

jre 默认安装完成之后:内部jre 外部jre

JDK8 在安装完之后,它会自己配置环境变量path

where java
echo %PATH%

可以path中把不需要的路径删除掉

可以path中把不需要的路径删除掉

set 可以临时设置环境变量
例如:
用一个路径【临时】把原来path的值给覆盖掉

set path=C:\Program Files\Java\jdk1.7.0_79\bin
echo %path%

在原来path配置上【临时】追加一个新的路径

set path=C:\Program Files\Java\jdk1.7.0_79\bin;%path%
echo %path%

注意,当前命令窗口一旦关闭,这些临时设置变量就失效了。

配置环境变量

JAVA_HOME PATH CLASSPATH
JAVA_HOME 变量 (默认情况下,操作系统中没有,属于自定义的环境变量)	
	目的:指明当前系统中安装的JDK的位置
	JAVA_HOME=C:\Program Files\Java\jdk1.8.0_74

PATH 变量 (默认情况下,操作系统自带的环境变量)

	目的:为了在命令行中,编译、运行java程序的时候,能够使用到jdk中的相关命令
	PATH=%JAVA_HOME%\bin;.........
	PATH=C:\Program Files\Java\jdk1.8.0_74\bin;.........

	注意,配置环境变量后,需要把当前命令窗口关闭然后重新打开

CLASSPATH 变量 (默认情况下,操作系统中没有,属于自定义的环境变量)
	目的:JVM在运行java代码的时候,需要在CLASSPATH这个环境变量所指定的路径的下,查找我们要运行的class文件中的代码。找到以后把代码加载到内存,然后运行。
	
	Hello.java --javac命令编译--> Hello.class
	Hello.java  源文件,里面存放的是java源代码
	Hello.class 字节码文件,里面存放的是java源代码编译后生成的字节
	JVM可以加载和运行Hello.class文件中的字节码
	
	CLASSPATH=.

	00001111 8位表示一个字节

	注意,检查一下自己的操作系统中,是否隐藏了已知文件的后缀名

JDK安装目录

	bin		目录 存放JDK自带的命令
	db		目录 JDK自带的一个小型数据库 
	include	目录 java底层部分是其他语言实现的(C/C++),相关代码存放在这里
	jre		目录 JDK中自动的java运行环境
	lib		目录 JDK中额外提供的一些jar包,jar中是别人开发好的代码/程序,我们可以直接调用。

	src.zip文件,JAVASE-API的源代码打成压缩包

	JVM只能加载运行class文件中的代码,不能加载运行java文件中的代码。
	java文件中的代码称为源代码
	class文件中的代码称为字节码

	其实JDK已经帮我们把src.zip中的源代码都编译成class文件字节码了,并且把编译好的这些class文件打成了一个压缩包,也就是jar包。而这个jar包,存在JRE中。
	JRE/lib/rt.jar 就是src.zip中源代码编译后打成的jar包

	JDK---》JAVASE-API ---》src.zip ---》 rt.jar

调用

1.java代码必须写在java文件中,也就是后缀是.java结尾的文件

	注意:检查系统是否隐藏了文件后缀名

2.java文件的名字,要求首字母大写

	例如: Hello.java  不要写成 hello.java
	注意:文件名首字母大写不是强制要求,而是编程规范
	注意:存放源代码的文件,称之为源文件

3.java源代码中,大多数情况都是以【类】为单位,去组织我们编写的代码

	注意:编译生产的class文件的名字,不是和java文件名字保持一致,而是和java类的名字保持一致,因为如果一个java类不是public的,那么这个类的名字是可以和java文件名字不一致的,但是最后编译生产的class文件会和类的名字保持一致。
	
	注意:一个java源文件中,可以编写多个java类,他们是平行/并列的关系,也就是说编译一个java源文件,可能同时生产多个class文件,每一个class文件都对应了这个java源文件中的一个java类

	注意:一个java源文件中,可以编写多个java类,但是最多只能有一个类是public的,而且如果这个类是public的,那么这个类的名字就必须和java源文件的名字保持一致。

4.在【类】中,就可以编写属性、方法、构造器等一些类代码了。

4.1 需要在java源文件中,编写出一个【类】的基本结构
		类的基本结构有三部分
		
		关键字、类名、一对大括号
		
		注意:java代码中,可能存在小括号、中括号、大括号,但是它们都是成对出现,所以如果我们每次编写括号的时候,最好一次写一对,这样就不会另外一边的括号了.
		
		例如:()  []  {}  注意,一定要是有英文输入法,来编写代码和这些括号

4.2 如果java源文件中,编写的类是public的,那么这个类的名字就必须和当前java源文件的名字保持一致。【强制要求】

4.3 类中的所有代码,都必须存放到类的那一对大括号中。

5.使用java命令运行是class文件中的类,而不是这个class文件,更不是java文件

运行java类的规则:
​	java 包名.类名
​	如果没有包名
​	java 类名

例如:	java Hello  正确的,运行这个名字叫Hello的类
	  java Hello.class 错误的
	  java Hello.java  错误的

注意:我们的java命令运行的是class文件中的类,而不是class文件本身,这个class文件只是我们类的载体.

6.JDK是向下兼容的

高版本的JDK编译出的class文件,使用低版本的JDK【无法】运行
低版本的JDK编译出的class文件,使用高版本的JDK【可以】运行

7.一个类如果想独立的运行起来,就是直接使用java命令去运行,那么这个类中一定要一个程序入口,就是一个名字叫做main的固定格式的方法。

7.1 普通类
	这个类中没有程序入口,不能独立运行,这种类的作用是让别人调用的,也就是说它虽然不能自己独立运行,但是可以让别人去调用这个类的代码。
	
​7.2 可以独立运行的类
	类中有程序入口,可以使用java命令直接去运行这个类。同时别人也可以调用这个类的代码。
	可以独立运行的类 = 普通类 + 程序入口

​7.3 程序入口
	在java中,程序入口是一个名字叫main的固定方法:
	public static void main(String[] args)
	
	一个系统中,代码写的再多,也得有一个起点,让程序从这里开始运行,那么这个起点我们就称之为程序入口.

	注意:java命令只能运行有程序入口的类,如果运行一个没程序入口的类,那么java命令会报出错误信息,提示没程序入口main方法。
​7.4 程序入口,在java中,称之为main方法、主方法、main函数、主函数.

​7.5 使用java命令去运行一个类,其实就是运行这个类中的程序入口,也就是main方法.

8.类中的代码编写

​ 一定要注意格式,不能把所以代码都顶满格从最左边开始写,需要使用tab键来体现出代码中的层次关系,这样可以提供代码的可读性,将来这个代码也方便维护。

注意:每次编写或者修改完java文件之后,都必须要重写编译java文件,保证接下来我们运行的是最新生成的class文件中的java类。

9.在java代码中,如果我们要是有别人已经写好类(代码),那么我们需要使用import关键字来引入这个类,目的是为了告诉JVM,我们要使用别人写好的这个类了,你帮我把这个类加载过来,供我们来调用。但是有俩种特殊情况,我们可以直接使用别人写好的类,而不需要import引入了

9.1 这个类是java.lang包下的类
	例如:java.lang包中的System这个类,我们在代码中可以直接使用,不需要import导入了。
	
9.2 这个类和我们当前所写的类是同一个包
	例如:A和B类这俩个类是在同一个包下,那么A中使用B类、或者B类中使用A类,都不需要import导入。

9.3 除以上俩种情况外,其他的情况,只要是使用了别人的类,那么都需要import引入,来通知JVM

10.把java代码编译成class之后,我们还可以把class文件打成一个jar包

10.1 jar包本质上其实就是一个压缩包,使用电脑中的解压缩软件,就可以直接把这个压缩包打开,也可以进行添加、删除和修改等操作。

10.2 使用jar命令,就可以完成class的打包工作,打包完成只会,jar中不仅有class文件,还有一些对当前jar做出描述的文件。/META-INF目录下生产一个MF文件

10.3 默认情况下,这个jar是不能直接运行的,也就是它不是一个可执行jar包,我们可以通过对MF文件的修改,让它变成一个可执行的jar包,前提是这个jar中的class文件里面的类中有程序入口。
	修改方式:
	在MF文件中添加一行内容
	格式:key: value
		 Main-Class: 包名.类名
	如果没有包,那么就直接写这个类,但是这个类里面一定要有程序入口。
	例如:Main-Class: Hello

	MF文件最后的样子:
	Manifest-Version: 1.0
	Created-By: 1.8.0_74 (Oracle Corporation)
	Main-Class: Hello

	注:这样以来,这个jar就变为了一个可执行jar包,通过java命令可以直接运行该jar包
	例如: java -jar hello.jar

10.4 jar包的打包方式:
	把当前目录下的Hello.class打到hello.jar这个jar包中
	命令格式:jar -cvf hello.jar Hello.class
	
	把当前目录下的Hello.class Person.class打到hello.jar这个jar包中
	命令格式:jar -cvf hello.jar Hello.class Person.class

	把当前目录下的所有的class打到hello.jar这个jar包中
	命令格式:jar -cvf hello.jar *.class
	
	把当前目录下的briup文件夹里面的所有文件打到这个jar包中,同时【包含】briup目录本身
	命令格式:jar -cvf hello.jar briup
	
	把当前目录下的briup文件夹里面的所有文件打到这个jar包中,但是【不包含】briup目录本身
	命令格式:jar -cvf hello.jar -C briup .

10.5 修改MF文件的时候容易出现的问题:
	单词拼写错误 
		错误示例:Mian-Class
		正确示例:Main-Class
	中英文输入法切换问题,冒号需要是英文输入法下输入的
		错误示例:Main-Class:Hello
		正确示例:Main-Class: Hello
	冒号后面需要加入空格
		错误示例:Main-Class:Hello
		正确示例:Main-Class: Hello
	MF最后要保留一个空行
		错误示例:
------------------------------------------------------------------------------------------------------------------------------

​		Manifest-Version: 1.0
​		Created-By: 1.8.0_74 (Oracle Corporation)
​		Main-Class: Hello
-------------------------------------------------------------------------------------------------------------------------------

​		正确示例:

------------------------------------------------------------------------------------------------------------------------------

​		Manifest-Version: 1.0
​		Created-By: 1.8.0_74 (Oracle Corporation)
​		Main-Class: Hello

-------------------------------------------------------------------------------------------------------------------------------

10.6 一个jar包中,调用了另外一个jar中的代码	
	例如:
	Person.class调用了Hello.class以及NumberUtils.class

	Person.class		在person.jar中	
	Hello.class			在hello.jar中	
	NumberUtils.class	在commons.jar中

	person.jar是一个可以直接运行的jar包,这时候,需要在person.jar中的MF文件里面进行设置:

--------------------------------------------------------------------------------------------------------------------------------

​	Manifest-Version: 1.0
​	Created-By: 1.8.0_74 (Oracle Corporation)
​	Main-Class: com.briup.test2.Person
​	Class-Path: hello.jar commons.jar

-------------------------------------------------------------------------------------------------------------------------------
​	注意1,最后一个空行必须要加
​	注意2,这个时候我们可以说person.jar依赖于hello.jar和commons.jar
​	注意3,这时候需要把person.jar、hello.jar、commons.jar放在同一个目录下,因为MF文件中是这样配置的:Class-Path: hello.jar commons.jar
​	注意4,如果MF中这样配置:Class-Path: jar/hello.jar jar/commons.jar  ,那么就说明hello.jar和commons.jar需要在jar这个目录中,然后jar这个目录和person.jar放在同一个路径中

10.7 person.jar包里面有com.briup.test2.Person.class,同时Person类的运行需要依赖hello.jar和commons.jar中的类
	这时候有俩种方式运行:
​		直接运行jar,这时候要求这个jar需要配置成可执行jar包(修改MF文件)
		java -jar person.jar
		注意:这时候需要把classpath配置到MF文件中,目的是为了让jar中的代码在运行的时候可以通过这歌classpath的配置找到对应的jar中的代码

​		以运行java类的方式去运行person.jar中的Person类,这时候在jar中的MF文件里面就不需要配置可执行jar包或者classpath了
		java com.briup.test2.Person
		注意:这时候需要在外面配置外面的系统环境变量,例如配置一个临时的变量set classpath=jar/person.jar;jar/hello.jar;jar/commons.jar

11.package对class所起到的作用

11.1 在程序中,要区分一些东西,一般会采用【命名空间】的设计方式
	
11.2 在java中,package其实就是class的命名空间,用来唯一标识这个类的

11.3 一般情况,这个包就是一个公司、组织、社团所在的网址,把网址倒过来写就是对应的包
	例如:http://commons.apache.org/ 
	这个官网下的项目代码中的包都是以pacakge org.apache.commons 开头的。

11.4 一个类加上包名,在编译之后这个包会有什么实际的效果?
	类的包在编译之后,都必须要有对应的文件夹
	例如: package com.briup.demo;
	注意,这里是三个包,编译完之后,需要有对应的三个文件夹分别是com/briup/demo ,在demo目录中,才有编译生产的class文件

11.5 一个类加上包之后的编译运行
	package com.briup.test;
	public class Hello{....}

	生成的class文件需要放到和包名对于的目录结构中:com/briup/test/Hello.class
	运行的时候需要加入包名:java com.briup.test.Hello

11.6 在编译一个带包的类的时候,可以添加命令参数,让编译器自动生成和包名对应的目录结构
	编译:
	javac -d . Hello.java
	运行:注意这时候%classpath%的配置
	java com.briup.test.Hello

11.7 一个类有俩个名字
	例如有这样一个类:
		package com.briup.test;
		public class Hello{
			//....
		}
		
​	简单类名: Hello
​	全限定名: com.briup.test.Hello

11.8 设置classpath
	永久生效:
		在我的电脑-》属性-》高级系统设置-》环境变量 
	当前命令行窗口内生效:
		set classpath=bin
		注意:当前窗口关闭,该变量的临时设置就失效了
	当前命令一次生效:
		java -classpath bin Hello
		简写为
		java -cp bin Hello
		注意:当前命令执行完,该变量的临时设置就失效了

11.9 一个带包的类A,调用一个不带包的类B
	老版本JDK可以调用,JDK1.1 1.2 1.3
	从JDK1.4(包含)往后,编译器在编译这样代码的时候会报错

12.java文件和class文件存放的规则

Xxxx.java  源文件存放到src目录
Xxxx.class 字节码文件存到bin目录

注意,这不是强制要求,而是编程规范	

13.class文件被JVM加载(类加载器)

注意:任何代码想要被运行,都必须先从磁盘中加载到内存中才行。

13.1 JVM启动之后,会创建一些类加载器,然后让这些类加载器去加载当前代码运行所需要的类。
	 注意:类加载器的作用:就是在JVM中,来加载硬盘上的编译好的java类

13.2 类加载器是什么
	 类加载器本质上也是一段代码,这段代码执行后,可以从指定位置上把编译好的java类从硬盘中读取到内存。

13.3 类加载器的种类
	 类加载器是个总称,它下面有很多不同种类、特点的个性化类加载器。
	 类加载器在java中,被称为ClassLoader,同时这个ClassLoader也是java SE API中提前写好的一个类。这个类的作用就是用来代表类加载器的。相当于我们写了一个类Person,用这个Person类来代表人,是一样的效果。
	 ClassLoader类 --代表--》 类加载器
	 Person类      --代表--》 人

JVM中,将类加载器分为以下几种:

启动类加载器 bootstrapClassLoader
	注意:这个类加载器 【不是】java代码实现的。
​	加载路径:
	C:\Program Files\Java\jdk1.8.0_74\jre\lib\
	自动加载这个路径下的指定jar,例如:rt.jar
	
​	在java中,使用这个变量来代表启动类加载器加载的路径:
	sun.boot.class.path
	
​	当前我电脑中运行后这个变量的结果为:
	C:\Program Files\Java\jdk1.8.0_74\jre\lib\resources.jar;
	C:\Program Files\Java\jdk1.8.0_74\jre\lib\rt.jar;
	C:\Program Files\Java\jdk1.8.0_74\jre\lib\sunrsasign.jar;
	C:\Program Files\Java\jdk1.8.0_74\jre\lib\jsse.jar;
	C:\Program Files\Java\jdk1.8.0_74\jre\lib\jce.jar;
	C:\Program Files\Java\jdk1.8.0_74\jre\lib\charsets.jar;
	C:\Program Files\Java\jdk1.8.0_74\jre\lib\jfr.jar;
	C:\Program Files\Java\jdk1.8.0_74\jre\classes

扩展类加载器 ExtClassLoader
	注意:这个类加载器 【是】java代码实现的。
​	加载路径:
	C:\Program Files\Java\jdk1.8.0_74\jre\lib\ext\
	自动加载这个路径下jar包

​	在java中,使用这个变量来代表扩展类加载器加载的路径:
	java.ext.dirs

​	当前我电脑中运行后这个变量的结果为:
	C:\Program Files\Java\jdk1.8.0_74\jre\lib\ext

应用类加载器 AppClassLoader
	注意:这个类加载器 【是】java代码实现的。
​	加载路径:
	环境变量 classpath 中设置的所有路径里面的的class文件
	
​	在java中,使用这个变量来代表应用类加载器加载的路径:
	java.class.path

​	当前我电脑中运行后这个变量的结果为:
	jar/commons.jar;bin

​	这个对应的值,就是在运行代码时候,自己设置的classpath变量值。可能每个人的设置不同而不一样。

注意:这些可以表示不同类加载器的加载路径的变量,在JVM运行的代码之后,就通过系统变量的形式提前收集好了,并且提供了对应API让我们调用,从而在程序中可以很轻松的获取到这些值。

例如:
package com.briup.test;
import java.util.Properties;

public class ClassLoaderTest{
	public static void main(String[] args){
		Properties p = System.getProperties();
		p.forEach((k,v)->System.out.println(k+"\t"+v));
	}
}

自定义加载器 XxxClassLoader
​	例如:在代码中还可以调用相应API,来看到java中所表示出的类加载器对象。

​	ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();
	System.out.println(appClassLoader);	
	//sun.misc.Launcher$AppClassLoader@2a139a55

​	ClassLoader extClassLoader = appClassLoader.getParent();
	System.out.println(extClassLoader);	
	//sun.misc.Launcher$ExtClassLoader@7852e922

​	ClassLoader bootClassLoader = extClassLoader.getParent();
	System.out.println(bootClassLoader);
	//null
	//注意:启动类加载在java中无法表示,因为它不是java语言实现的。所有这里输出null

13.4 多个类加载器之间共同协作,然后把我们的编写的类加载到内存去执行
	
	这三个类加载器共同协作,使用【双亲委托】的方式,把一个class文件中的类加载到内存
	
​	例如:要运行Hello.class文件中的类,首先加载任务就交给了AppClassLoader,然后AppClassLoader又这个任务委托给自己的父加载器,也就是ExtClassLoader,然后ExtClassLoader也会把这个任务继续委托给自己的父加载器,也就是bootstrapClassLoader,然后bootstrapClassLoader就尝试去加载Hello这个类,但是在指定路径下并没有找到,然后这个任务就又交给了ExtClassLoader,这时候ExtClassLoader就尝试加载Hello这个类,但是在指定路径中也没找到,然后这个任务又交给了AppClassLoader,最后AppClassLoader从classpath中指定的路径里面找到并加载了这个Hello类,完成类加载的过程。	

启动类加载器 bootstrapClassLoader
​	加载路径:
	C:\Program Files\Java\jdk1.8.0_74\jre\lib\		
	注:这个类加载器专门加载java系统中最重要最基本的类

扩展类加载器 ExtClassLoader
​	加载路径:
	C:\Program Files\Java\jdk1.8.0_74\jre\lib\ext
	注:这个类加载器专门加载系统中额外添加的一些功能的jar包

应用类加载器 AppClassLoader
​	加载路径:
	用户自己设置的classpath变量中的路径
	注:这个类加载器专门加载系统中用户自己编写的项目代码

	硬盘上:Hello.class	
	java.lang.String 里面是自己写的破坏性代码
	想把rt.jar里面的java.lang.String给替换了
		
	双亲委托可以避免恶意和系统中同包同名的类被加载到内存,替换系统中原有的基础类,而导致系统崩溃的情况发生。

============================================================================================================================

14.java提供了解释执行的环境

java其实并不是真正的编译语言
Hello.java --编译-->  Hello.class  --加载-->  JVM  --解释字节码--> 计算机执行

14.1 可以提高开发的速度

14.2 Write once, run anywhere
	一次编写/编译,到处运行
	跨平台
	不同的平台,就意味着操作系统不同,那么操作系统内核不一样,操作支持执行的机器语言也不同,所以真正的编译语言,一般只是针对当前系统中的内核来编译成机器码运行,如果换了平台,这个编译好的机器码就不能执行了。

java语言为什么可以跨平台?
	因为java在不同平台都有针对平台的不同虚拟机,所以其实java语言虽然跨平台了,但是JVM在不同的平台下,发了不同的变化。

14.3 支持多线程

14.4 支持动态升级(JRE)

15.java提供了更加简单的编程方式

15.1 没有指针
	一些其他语言中,程序员要自己控制指针来针对不同数据的操作,但是在java中,没有指针这个概念。

15.2 代码中没有内存管理
	一些其他语言中,程序员要自己控制内存的分配、使用、释放,如果操作不当,会引发内存溢出/泄露的情况,这些都是程序中比较严重的问题。但是在java中,程序员不需要自己来控制内存的分配、使用、释放等操作,这些事情在JVM中,会帮我们一一搞定的。

15.3 纯正的面向对象编程
	在java中,一切皆为对象,做任何操作都是需要通过对象的,例如调用方法、访问属性都是要通过对象来操作的。但是static修饰的方法和属性,除了使用对象访问之后,还可以使用类名来访问。

16.垃圾回收器

16.1 java中不需要自己分配内存
	java中有一个关键字:new
	同时它也代表了一个操作:创建对象的操作。
	使用new关键字,就表示我们要在java中创建对象,在创建对象之前,new关键字会在内存中自动为我们申请一块空间,用来存放即将创建来的对象,同时我们要用的数据,也存在这块内存中。

​	例如:Person p = new Person(1,"tom",20);
​	这是可以new关键字,来创建Person类的一个对象,也称之为一个实例,同时在内存中申请一块内存空间,存放这个对象,并且把对象中的数据也存进来。
​	代表的含义是:这个人的编号是1,名字是tom,年龄是20

16.2 new关键字创建对象使用了内存,用完后,最终要把内存释放掉
	这个工作也不需要我们程序员来管理。
	JVM中一个东西叫垃圾回收器
	
	作用:回收内存中使用过,现在已经不用了的内存空间
	
16.3 垃圾回收器是什么?
		其实垃圾回收器也是JVM中的一段代码,它运行之后可以帮我们回收不再使用的内存空间,以便让接下来的代码继续运行使用。

16.4 我们是否能控制垃圾回收器去回收内存垃圾
	不能。我们只能通过调用相关的API去【建议】垃圾回收器去清理内存垃圾,但是它是不是真的就立马去了,这个是不一定的,我们控制不了,需要根据当前内存的使用情况,和垃圾回收器内置的算法来决定。
	对应的API调用方法:
		java.lang.System.gc();
		java.lang.Runtime.gc();

17.字节码验证

一个class文件被加载到JVM内存之后,首先要经过字节码验证,验证通过过,再确定哪些代码是解释执行的,哪些代码是JIT即时编译执行的。

17.1 字节码验证
	检查当前class文件的版本和JVM的版本是否兼容
	检查当前代码是会破坏系统的完整性
	检查当前代码是否有栈溢出的情况
	检查当前代码中的参数类型是否正确
	检查当前代码中的类型转换操作是否正确
	...
	...

17.2 解释执行
	java语言不是真正的编译语言,编程的class文件,需要让JVM进行解释,解释成计算机可以执行的代码。整体效果就是JVM解释一行代码就执行一行代码。

所以如果java代码全是这样的运行方式的话,效率会稍低一些。

17.3 JIT(Just In Time)即时编译
	它是JVM中执行java代码的一种方式,JVM可以使用JIT把java中的热点代码直接编译成计算机可以运行的代码,这样接下来再调用这个热点代码的时候,就可以直接使用编译好的代码让计算机直接运行,可以提高运行效率。

18.java中一些重要的包

java.lang包
	最常用的一个包,里面的类可以在我们的程序中直接使用,不需要import导入

java.awt包
javax.swing包
java.awt.event包
	这三个包属于同一类型的,它们包下面的类都是用来做图形化界面的(GUI)
	注意:javax开头的包,是sun公司后面又扩展进来的包,刚开始是没有的

java.io包
	这个包下的类主要用于输入输出流的操作。也就是读数据/写数据

java.net包
	这个包下的类主要用于网络编程。例如把计算机A和计算机B之间建立网络连接,然后进行信息传输。

java.util包
	这个包下的类都是一些常用工具类,可以帮我们在代码中完成一些辅助的功能,例如表示日期、使用集合存储数据、使用工具类操作数组等

19.java中的注释(文档注释Javadoc)

19.1 在java源代码中写的注释,程序员可以看见,但是编译之后,class文件中是没有这些注释的。所以注释是给程序员看的,不是给JVM看的。

被注释掉的代码、文字是【不会】被解析和执行的。

代码中的注释,一般都是用作对当前代码的一个描述或者解释或者介绍以及一些用法的样例。

19.2 在java中,有三种注释方式:

// 单行注释

/* 多行注释 */

/* 
	多行注释 
	多行注释 
	多行注释 
*/

/** 
* 文档注释 
*/

注意,单行注释和多行注释都属于java中的普通注释,而文档注释是java中比较特别一些的注释

19.3 文档注释
	首先文档注释是具备多行注释的能力的,其次文档注释编写完成之后,还可以配合javadoc命令,将文档注释的内容抽出来,自动生成相应的API说明文档。
	
Javadoc命令格式: javadoc [选项] [软件包名称] [源文件]

​	注意:javadoc命令生成的API文档是html页面形式的。

​	javadoc -d api src/CommentsDocTest.java

19.4 文档注释中的标记
	文件注释中,以@符合开头的就是文档注释标记。这些标记是java中规定好的,我们并不能随意乱写。并且每一个都是具体的含义。

​	@author		作者
​	@version	版本
​	@since		开始启用的时间
​	@see		另参照
​	@param		方法的参数
​	@return		方法的返回值
​	@throws		方法可能会抛出的异常


​		

​	注意,如果不加参数-author -version,那么作者和版本就不会默认显示出来

​	javadoc -encoding utf-8 -d api -author -version src/Comments*.java

​	javadoc -d api -author -version src/Comments*.java

20.分号、代码块{}、空白

20.1 java中,每句代码都是以分号结束。(英文输入法下的分号)
	需要分号的地方:
​	包的声明
		package com.briup.test;
		

​	类的引入
		import java.util.Date;

​	属性的声明
		public class Person{
			public String name;
		}
	
​	方法中的几乎所有代码(将来会有些特例,不用分号,但是很少)
		public void go(){
			int a = 1;
			int b = 2;
			int c = a+b;
			System.out.println(c);
		}

注意:将来代码解析执行但时候,怎么来确定哪些代码是属于同一句,那么就是根据代码后面的分号来确定的。
例如:
	int a = 1;int b = 2;

​	虽然是在同一行,但是这里是俩句代码。

所以为了没有歧义,我们一般尽量是一句代码独占一行。
例如:
	int a = 1;
	int b = 2;

20.2 有些情况下,不需要加分号
	类的声明
	例如:
		public class Hello{}

​	最后【不需要】加分号

​	public class Hello{};


​	

方法的声明
例如:
public void go(){}

最后【不需要】加分号

public void go(){};

20.3 代码块
	在java中,使用{}括起来的就是代码块。它表示一种代码范围的划分。
	例如:public class Hello{}
	

这里Hello后面的大括号就表示这里面的代码全都属于Hello这个类的。

例如:public void go(){}

这里go后面的大括号就表示这里面的代码全都属于go这个方法的。

注意:代码块最后,也就是大括号最后,都是不加分号的。(只有很特殊的情况加)

20.4 代码中的空白区域
	在代码中,我们可以使用空格、tab、新行、回车,并且对代码是没有影响的
	例如:
		public class Hello{}
		加上空格、tab、新行、回车等之后,变为如下,但是下面代码依然是正确的可以编译执行的。
		public       class					Hello
			{
	
	

​			     }

例如:
	int a=1;
	int a = 1;
	int a	=	1;
	int a
	=
	1;
	这四句代码的效果是一样的。


​	

但是不能使用这些对象分割单词或关键字
例如,如下代码是编译报错的
	pu	blic cla	ss	Hel
	lo{}
  1. 标示符
    在java中,给类、方法、变量起的名字,就是标示符,因为它可以用来标识这个类、方法、变量。

    21.1 标示符的命名规则

    标示符可以由字母、数字、下划线_ 、美元符号$组成
    	0-9 a-z A-Z _ $
    标示符开头不能是数字
    标识符中的字符大小写敏感
    标识符的长度没有限制
    标示符不能使用java中的关键字或保留字
    标识符尽量起一些有意义名字(强烈建议)
    
    合法标示符			非法标示符
    	try1				try#
    	GROUP_1				1GROUP
    	helloworld			hello-world
    	_int				int
    	$int				$-int
    

    22.2 推荐规则
    类名首字母大写,如果是俩个单词,那么第二个单词首字母也要大写

    方法名和变量名都是首字母小写,如果是俩个单词,那么第二个单词首字母也要大写
    
    同时,名字尽量有意义
    
  2. 关键字
    关键字和保留字,都不能作为标示符来使用。

    建议,把这些关键的拼写都在键盘上练熟

  3. java中的基本数据类型

    23.1 基本数据类型,也称为简单的数据类型,是java语言中,可以表示出来的最基本数据的结构。

    23.2 计算机中字节的含义
    计算机存储数据的时候,都是以二进制0101代码进行存储的。
    例如,十进制的数字10,计算机存的时候需要变为二进制见存储00001010

    计算机存数据有一个基本的单位:字节
    每8位0101代码,就称为一个字节
    
    8位=1字节
    
    1KB=1024B=1024个字节
    

    23.3 每种数据都有自己的类型,以下几种数据类型,是java中能表示的最简单的数据类型
    整数型
    byte 8位 1字节
    short 16位 2字节
    int 32位 4字节
    long 64位 8字节

    浮点型
    	float		32位	4字节
    	double		64位	8字节
    
    字符型
    	char		16位	2字节
    
    布尔型
    	boolean		8位		1字节
    


​ 23.4 布尔类型
​ boolean 8位 1字节

​ true|false

​ boolean a = true; 0000 0001
​ boolean b = false; 0000 0000


​ 23.5 文本数据类型
​ char 和 String 可以表示文本数据

​ char是基本的数据类型,最简单的数据类型

​ String是java中的类,类是java中复杂的数据类型

注意,类是一种复杂的数据类型,在内存中可能会占据成百上千位(0101代码)的内存空间,但是基本数据类型最多也就是占据64位内存空间,这个char仅仅只会占据16位的内存空间。

	注意,char是基本类型而不是java类,不能使用new来创建对象,String是类,可以使用new创建对象。

	注意,中文里面的每一个汉字,都是一个字符

	注意,java中,默认采用Unicode编码

	char c = 'a';
	char c = 97;

	String s = new String("a");
	字符串String使用频率太高,JVM给了一个简洁写法:
	String s = "a";


	String是字符串,char是字符,字符串就是把字符给串起来。
	String字符串是由0个或多个字符(char)组成的文本数据。
	
	String s = "";		0个字符组成
	String s = "a";		1个字符组成
	String s = "hello";	5个字符组成

	注意:八种基本类型任何一种,和字符串相加,结果都会变成字符串
	例如:
		String	s = ""; //空字符串,由0个字符组成
		boolean a1 = true;
		char	a2 = 'a';
		byte	a3 = 1;
		short	a4 = 1;
		int		a5 = 1;
		long	a6 = 1;
		float   a7 = 1.5F;
		double  a8 = 1.5D;

		a1+s //结果 "true"
		a2+s //结果 "a"
		a3+s //结果 "1"
		a4+s //结果 "1"
		a5+s //结果 "1"
		a6+s //结果 "1"
		a7+s //结果 "1.5"
		a8+s //结果 "1.5"


​ 转义字符
​ 对于一些特殊字符,例如单引号,双引号等,在代码中不能直接表示出来,例如在字符的单引号中不能直接表示出单引号,在字符串的双引号中,不能直接表示出双引号。
​ char c = ‘’‘; // 错误
​ String s = “”";// 错误

​ 这时候可以使用转义字符:\ ,它可以把一个原本有特殊含义的字符转成一个普通的字符。
​ char c = ‘’’; // 正确
​ String s = “”";// 正确

​ char c = ‘\’;//第一个转义字符,把第二个转义字符 给转义了

		使用转义字符,在代码中表示回车、换行、tab
		char c1 = '\r'; //回车
		char c2 = '\n'; //换行
		char c3 = '\t'; //tab
		
		String k = "...";
		String v = "...";
		System.out.println(k+"\t"+v);

23.6 整型类型
	整型有四种,专门用来表示整数的,包含正负整数
	byte	8位		1字节

	short	16位	2字节

	int		32位	4字节

	long	64位	8字节


	byte a1 = 1;  
		0000 0001
	long a2 = 1;
		0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001


	java中整型数据类型是带符号位的,首位是0代表正数,首位是1代表负数。
	正数1
		0000 0001
	
	正数 取反再加1 得到对应的负数
	负数 取反再加1 得到对应的正数

	取反操作就是把所以位上的0变1,1变0

	正数1 取反再加1 得到负数1

		0000 0001	正数1
		取反
		1111 1110
		加1
		1111 1111	负数1

	--------------------------------	

		1111 1111    负数1
		取反
		0000 0000
		加1
		0000 0001	 正数1


​ 二进制和十进制转换
​ 0000 1011 转十进制

​ 12^0 + 12^1 + 02^2 + 12^3

​ 1 + 2 + 0 + 8 = 11



​ 11 转二进制:除以2取余数
​ 2 11 1 11除以2余数是1 商是5
​ ----
​ 2 5 1 5除以2余数是1 商是2
​ ----
​ 2 2 0 2除以2余数是0 商是1
​ ----
​ 2 1 1 1除以2余数是1 商是0
​ ----
​ 0

​ 最后把余数按顺序倒着写就是11对应的二进制 1011
​ 注意,1011 是把前面的一些0给省去了,写完整就是 0000 1011


​ 在java程序中,整型可以使用二进制 八进制 十进制 十六进制来表示数字

​ 例如:
​ byte a1 = 20; // 十进制 20
​ byte a2 = 024; // 八进制 20
​ byte a3 = 0x14; // 十六进制 20
​ byte a4 = 0b00010100; // 二进制 20

	java中整型数据的默认类型是int
		
		例如:这个要打印的数据的字面值是1,它的类型是默认类型int
		System.out.println(1);
		注意,像这样的情况,我们如果不知道数据的类型,那么这个整型数据的默认类型就是int

		注意:
		一个位数多的数据类型,转换为一个位数少的数据类型,都是有可能会损失的
		一个位数少的数据类型,转换为一个位数多的数据类型,是不会有损失的


​ java是强类型编程语言,要求数据的类型和变量的类型保持一致,才能使用=号进行赋值,就是把=号右边的数据,赋值给=号左边的变量
​ 例如: long a = 1L;

​ 如果=号右边的数据和=号左边的变量类型不一致,那么只能做类型转换,把数据的类型转为变量的类型,然后才能完成=号赋值操作。只是类型转换的过程,分为手动转换和自动转换。
​ 例如:手动转换
​ int a = 1;
​ byte b = (byte)a;

​ 例如:自动转换
​ byte c = 1;
​ int d = c;

	long类型的数据,在声明的时候,需要使用L来标注

	例如:
		long a = 1L;

23.7 浮点型数据
	以下俩种是java中的浮点型数据
	float		32位	4字节
		1符号位+8指数位+23尾数位  小数点后的精确度在7位左右
	double		64位	8字节
		1符号位+11指数位+52尾数位 小数点后的精确度在16位左右

	可以用来表示小数。

	浮点型数据的声明
		
	例如:
		float  a = 10.5F;
		double b = 10.5D; 
		
		注意:float数据后面加F/f
		注意:double数据后面加D/d



​ 浮点型数据的默认类型是double
​ 例如:
​ System.out.println(10.5);

​ 注意,这个数据10.5默认就是double类型的

  1. 变量的声明和赋值
    注意,程序中的所有变量,都必须要严格按照 先声明,再赋值,再使用 的步骤。

    24.1 在java中,使用某一种数据类型,去声明出一个变量,使用这个变量就可以去接收/保存 该数据类型所对应的数据了。

    24.2 变量的作用
    任何编程语言中,都有变量,它们的作用是一样的,都是为了在程序运行期间,使用变量去 接收/保存/传递/计算/操作 程序中需要用到的数据。

    24.3 变量的声明
    格式:
    数据类型 变量名;

    例如: 声明一个int类型的变量a
    	int a;
    	
    	注意,这个变量a,就可以用来 接收/保存/传递/计算/操作 int类型的数据
    

    24.4 变量的赋值
    编译语言中的=号,和之前数学中使用的=号,含义是不一样的,数学里面的=号表示=号等号俩边的值相等,但是编程语言中的=号,指的是赋值操作。把=号右边的值付给=号左边的变量,并且要求数据的类型和变量的类型是一致的。

    先声明变量,再给变量赋值
    例如:
    	int a; //声明变量
    	a = 1; //给变量赋值
    
    
    声明变量的同时,就进行赋值
    	int a = 1;
    
    
    特殊形式,还可以同时声明多个不同名字的变量
    例如:
    	同时声明四个int类型的变量
    	int a,b,c,d;
    	
    	分别给四个变量赋值
    	a = 1;
    	b = 2;
    	c = 3;
    	d = 4;
    
    实例:
    //声明变量a
    int a;
    
    //给变量a赋值
    a = 1;
    
    //使用a的值,让a的值参与运算, 并且把运算结果赋值给变量b
    int b = a+1;
    
    //使用a的值,让a的值当做参数,传给println方法,在方法中将a的值见打印输出
    System.out.println(a);
    
    //使用a的值,让a的值参与运算,并且把运算结果赋值给变量a
    //=号是赋值操作,赋值操作需要先执行右边,算出结果后,把结果赋值给左边变量
    //先执行右边运算的时候,a的是还是原本的1,a+1的结果就是2
    //然后执行=号赋值操作,把结果2赋值给变量a,这时候变量a的值就变成了2
    a = a+1;
    

    24.5 变量的分类(根据数据类型)
    基本数据类型的变量
    使用基本数据类型声明出来的变量,就是基本数据类型的变量,简称基本类型变量

    	byte short int long 
    	float double
    	char
    	boolean
    
    注意,声明变量的格式为:数据类型 变量名;
    
    
    引用数据类型的变量
    	使用引用数据类型声明出来的变量,就是引用数据类型的变量,简称引用类型变量,或者简称为 引用
    	java中有无数个引用数据类型,可以分为三大类:类类型、接口类型、数组类型
    	使用类这种数据类型声明出的变量就是引用类型变量/引用
    		例如:
    			String str;
    			Person p;
    			注意,String和Person都是类类型
    			变量str和变量p就是引用类型变量
    	使用接口这种数据类型声明出的变量就是引用类型变量/引用
    		例如:
    			Action a;
    			Run	r;
    			注意,Action和Run都是接口类型
    			变量a和变量r就是引用类型变量
    	使用数组这种数据类型声明出的变量就是引用类型变量/引用
    		例如:
    			int[] arr1;
    			String[] strs;
    			Action[] arr2;
    
    			变量arr1和变量arr2、strs就是引用类型变量
    

    24.6 基本类型变量和引用类型变量的区别

    核心区别:基本类型变量不能指向对象,引用类型变量可以指向对象。
    
    例如:
    	Student stu = new Student(); //这是正确的,引用类型变量可以接受对象。
    
    	int a = new ... //这是错的,基本类型变量不能接受对象
    


​ 注意,只要引用类型变量才可以指向对象,指向对象之后,就可以调用到对象中的方法了,也可以访问到对象中的属性了,如果有权限的访问的话(public)

​ 注意,基本类型变量,和调用对象中的方法以及访问对象中的属性等这些操作,就无缘了。(就是基本类型变量做不了这个事情)

  1. 理解对象
    生活中,我们所接触到的或者使用到的所有事物,都是对象。
    例如现在上课用电脑、杯子、桌子、凳子、吃饭用的碗、筷等都是对象。
    在面向对象的思想中,万事万物一切皆为对象。

    java是面向对象编程语言中的一种,所有java中也是需要有这样的思想的。

    25.1 类和对象的关系

    对象是需要使用类来进行创建的(结合new关键字)。
    
    类是对事物的一种抽象的概括性的描述。类是抽象的描述
    
    对象是事物的一种具体的个体表现。对象是具体的体现
    
    
    public class Student{
    	public long id;
    	public String name;
    	public int age;
    	
    	public void run(){
    	
    	}
    	
    	public void play(){
    	
    	}
    
    }
    
    Student stu = new Student();
    stu.id = 1;
    stu.name = "zs";
    stu.age = 18;
    stu.run();
    stu.play();
    
    Student stu2 = new Student();
    stu.id = 2;
    stu.name = "lisi";
    stu.age = 19;
    stu.run();
    stu.play();
    

    25.2 JVM中的类和对象
    首先类编译后,会被类加载器加载到内存,就是我们编写的类中的代码就保存到了JVM管理的内存中,这时候,如果我们使用new关键字来创建这个类的对象,那么就会先在内存中申请一块空间,准备存放创建出的对象,然后根据内存中之前保存的java类的代码,来创建对象,刚刚申请到的内存空间,就保存这个对象的信息,这个对象的信息,就和java类中所定义的属性和方法保持一致。
    也就是当前我们在类中定义哪些属性和方法,那么在这个对象中就有这些属性和方法的信息,并这些信息都保存在new关键字申请到的那个内存空间中,所以这个内存空间就是我们所说的对象,在JVM中的表现形式。

    25.3 创建类的实例
    注意,实例和对象在java中,大多数情况下都是指的的同一个意思。
    所以以下说法都是正确的:
    创建类的实例
    创建类的对象
    把类进行实例化,得到这个类的一个对象/实例

    需要使用new关键字和类中的构造器,结合在一起来创建对象/实例
    	new 构造器
    
    注意,一个类中,如果我们没主动的去编写一个构造器,那么JVM会自动的帮我们给这个类添加一个无参的构造器。
    所以,我们在写完一个类之后,直接创建对象,就是因为编译后,类中多了一个自动生产的无参构造器。
    但是如果我们在自己写类的代码时候,手动编写了一个构造器,那么编译之后,就不会自动生成其他构造器了。
    

    25.4 区分类中的属性、方法、构造器

    类中的属性和方法区别在于:
    	属性名后面是没有小括号的,而方法名后面一定是有小括号的,这个小括号就代表方法的参数列表,也就是方法有没有参数、参数有几个、参数分别是什么类型的,这些都是在小括号中体现出来的。
    
    	属性其实就是类中的一个变量,可以把对象相关的值,保存到这个属性中
    	方法后面是有一个大括号的,大括号中是可以编写代码的,将来使用对象调用这个方法时候,大括号中的代码就可以一行行的顺序执行了。
    
    构造器和方法的区别:
    	构造器的名字和类名是必须要保持一致的,但是方法的名字我们是可以随意命名的,只要满足标示符的命名规则就可以了。
    
    	方法的声明中是一定有返回类型的,就是真的方法执行完不返回任何数据,我们也需要用void关键字来表示出来。
    	但是构造器是一定没有声明类型的,并且也没void关键字。
    	例如:
    	public class Person{
    		//这是类中的构造器
    		public Person(){}
    		//这是类中的一个普通方法,只不过方法名字起得和类名一样
    		public void Person(){}
    
    	}
    
  2. 变量的范围
    代码中的变量是有作用范围的,就是一个变量在代码中声明好之后,我们在什么地方是可以访问这个变量的,在其他什么地方是不能访问这个变量的。

    根据变量的作用访问的不同,可以分为局部变量和实例变量

    26.1 局部变量

    位置:
    	方法的大括号中或者方法的参数列表中
    	在方法的大括号中定义的变量 和 方法的参数列表中定义的变量 都是局部变量
    
    	例如:
    		public void test(int a){
    			int b;
    			if(a>0){
    				b = 1;
    				int c = b+2;
    			}
    		}
    
    		这里面的 变量a和变量b和变量c都是局部变量
    
    作用范围:
    	如果是定义在方法的参数列表中的局部变量,那么在这个方法的大括号中的任意位置,都是可以访问到这个变量的
    	例如:
    		public void test(int a){
    			
    			System.out.println(a);
    
    			{
    				System.out.println(a);
    				{
    					System.out.println(a);
    				}
    			}
    
    			if(true){
    				System.out.println(a);
    			}
    
    		}
    
    
    	如果是定义在方法的大括号中的局部变量,这个变量的作用范围就是和这个变量最接近的一对大括号之中。
    
    	注意,也可以观察这个局部变量是【直接】位于哪一对大括号中
    
    	例如:
    		public void test(){
    			
    			int a;
    
    			{
    				int b;
    			}
    			System.out.println(b); //报错,访问不到变量b
    			System.out.println(a); //不报错,可以访问到变量a
    		}
    


    ​ 默认值:
    ​ 局部变量是没有默认值的,也就是如果没给局部变量赋值的话,这个变量是不能使用的。

    ​ 但是方法的参数列表里面的变量,没有赋值的话,我们在代码中是可以直接使用的,这是因为这个变量是方法的参数,将来调用方法的时候,一定会把数据传给这个参数的。所以我们在方法中写代码的时候,这个参数列表中的变量是可以直接使用的。

    ​ 例如:
    ​ public void test(int a){

    System.out.println(a);

    		int b;
    		//下面代码编译报错,错误信息是变量b没有初始化
    		//所有这样的【局部变量】,一定要先【声明】、再【赋值】,然后再【使用】
    		//当然也可以只声明这个变量,但是不赋值,同时也不使用
    		System.out.println(b);
    }
    
    	main:
    		//将来在调用这个方法的时候,参数a一定是会有值的
    		t.test(1);
    


​ 生命周期:
​ 局部变量在被声明的时候,就产生了,再被赋值之后,就可以使用了,并且在这个变量的作用范围之内,我们都可以使用它。
​ 变量在内存中也是一小块内存空间,里面存的东西比较少,基本类型变量顶多存个64位的数据,引用类型变量也就是存一个对象的内存空间地址值。

​ 变量生命周期的最后,就是什么时候这个变量对应的内存空间会被释放。
​ 方法中的代码执行的时候,是从上往下一行行顺序执行的,当代码执行超过这个变量的作用范围,也就是它【直接】位于的那对大括号的时候,这个局部变量就会被释放了。

​ 例如:test方法中的代码执行完,变量a将会被释放
​ public void test(){
​ int a;

}

			if条件代码执行完之后,局部变量a就会被释放了
			public void test(){

				if(true){
					int a = 1;
					...
					...
				}
				//这里访问不到变量a,以为这时候变量a已经被释放了
				System.out.println(a);
			}

		注意:局部变量的生命周期,其实和局部变量的作用范围是保持一致的。


26.2 实例变量
	又可以被称之为属性、成员变量
		属性:
			大多数编译语言里面都是会这样叫的,而且在这里叫属性也很合适。
		成员变量:
			我们定义在类中的属性、方法都称之为类中的一个成员,所以会有成员变量和成员方法这样的叫法。
		实例变量:
			在java中,类的实例指的就是对象,这种变量只能使用对象/实例来访问,所以会叫做实例变量,如果没有对象/实例,那么这个变量是不能被访问的。

	位置:
		直接在类中定义的变量,就是实例变量/属性/成员变量


		例如:
			public class Student{
				private String name;
			}


	作用范围:
		类中的实例变量,是可以在类中定义的所有方法中进行访问的。
		注意,这里暂且不考虑静态和非静态的问题。

		public class Student{
			private String name;

			public void test(){
				System.out.println(name);
			}

			public void run(){
				System.out.println(name);
			}

			public static void main(String[] args){
				//这里不能访问name,因为程序入口是static,而name是非static的
				System.out.println(name);

				//如果想在static方法中访问非static的属性name,那么需要使用对象来访问
			}


​ }

	默认值:
		类中的实例变量,是有默认值的,也就是当我们声明了一个实例变量之后,不需要我们赋值,这个变量就会自动有一个默认值。
		
		但是不同类型的变量的默认值,是不一样的:
		整型的默认值都是0
		浮点型的默认只都是0.0
		字符型的默认值是'\u0000'  
		char c1 = '\u0000';
		char c2 = 0;
		boolean类型的默认值是false
		
		所以引用类型的默认值都是null

	生命周期:
		实例变量,是属于对象的(类中的静态变量,是属于类的),因为当对象创建出来的时候,这个对象中就有了这些实例变量,当这个对象在被使用完之后,如果后面不再使用了,那么垃圾回收器就会帮我们把这个对象所占用的内存给释放掉,那么同时对象中的实例变量也会被释放掉。

		只要这个对象存在,没有被GC给释放掉,那么对象中的实例变量就会跟着对象一直存放,我们就可以使用对象来访问这些实例变量。

		所以实例变量的创建、使用、销毁(释放),是和对象的创建、使用、销毁(释放)保持同步的。
  1. java中的操作符

    27.1 赋值操作符

    =  最基础的赋值操作符  
    	例如:int a = 1; int x = 0;
    
    *= 一个变量和另一个数据相乘,并把结果再赋值给这个变量
    	例如:int a = 1; a*=2; //a = a*2;
    
    /= 一个变量和另一个数据相除,并把结果再赋值给这个变量
    	例如:int a = 2; a/=2; //a = a/2;
    
    %= 一个变量和另一个数据相余,并把结果再赋值给这个变量
    	例如:int a = 5; a%=2; //a = a%2;
    
    += 一个变量和另一个数据相加,并把结果再赋值给这个变量
    	例如:int a = 5; a+=2; //a = a+2;
    
    -= 一个变量和另一个数据相减,并把结果再赋值给这个变量
    	例如:int a = 5; a-=2; //a = a-2;
    

    27.2 比较操作符
    注意,比较操作符的结果是boolean类型的
    和数字相关的比较操作符
    >
    例如
    int a = 1;int b = 2;
    boolean result = a>b;
    System.out.println(result);

    >=
    	例如 
    	int a = 1;int b = 2; 
    	boolean result = a>=b;
    	System.out.println(result);
    
    <
    	例如 
    	int a = 1;int b = 2; 
    	boolean result = a<b;
    	System.out.println(result);
    
    <=
    	例如 
    	int a = 1;int b = 2; 
    	boolean result = a<=b;
    	System.out.println(result);
    


    ​ 注意:
    ​ //char类型也可以比较,比较的是把字符进行编码后的数值大小
    ​ char c1 = ‘a’;//97
    ​ char c2 = ‘b’;//98
    ​ result = c1<c2;

    ​ //boolean类型数据不能比较,编译报错
    ​ //boolean b1 = true;
    ​ //boolean b2 = false;
    ​ //result = b1<b2;



    ​ 和对象相关的比较操作符
    ​ instanceof
    ​ 判断一个指定的对象,是否【属于】另一个指定的类型
    ​ 例如:
    ​ o instanceof Person
    ​ 表示引用o所指向的对象的类型,是不是属于Person
    ​ 并【不是】引用o声明的类型,是不是属于Person

    ​ 例如:
    ​ Student s = new Student();

    ​ boolean result;

    result = (s instanceof Student);

    		result = (s instanceof Object);
    
    
    	注意,一个java对象【a】,一定是使用了java中的某一个确定的类型【X】来创建出来的,这时候,我们就可以说这个对象a属于这个类型X,但是java中的类并不是一个单一的形式,类型和类型之间可能有继承或者实现这种关系,例如这里的类型X可能继承了父类A,同时有实现了接口B和接口C,在这种情况下,对象a既属于X类型,又属性A类型,又属性B类型,又属性C类型。使用instanceof来判断的话,返回结果全都是true
    
    
    例如:
    	在做一个对象的类型强制转换的时候,可以使用instanceof关键在,来判断一下这个对象是否属于接来下要做强制转换的那个类型,如果返回true,则说明我们接下来是【可以】做类型强制转换的,如果返回false,则说明接下来【不能】做类型强制转换。
    
    	Object obj = ....;
    
    	if(obj instanceof Student){
    		Student s = (Student)obj;
    	}
    

    27.3 相等操作符

    ==  
    	比较两边的数据是否相等,相等返回true,不相等返回false
    
    !=
    	比较两边的数据是否不相等,相等返回false,不相等返回true
    


​ 比较基本类型数据是否相等
​ 注意,基本类型数据就是八种

​ 例如:
​ boolean result;

​ int a1 = 1;
​ int b1 = 1;

result = (a1==b1);

		float  a2 = 10.5555555555555555555555555555555555555555F;
		double b2 = 10.5555555555555555555555555555555555555555D;

		result = (a2==b2);

		char a3 = 'a';
		char b3 = 'a';
		
		result = (a3==b3);


		boolean a4 = true;
		boolean b4 = true;
		
		result = (a4==b4);

		System.out.println(result);



	比较引用类型数据是否相等
		注意,引用类型数据其实也就是对象

		例如:
		//对象之间的比较
		OperatorTest t1,t2;
		
		//t1 = new OperatorTest();
		//t2 = new OperatorTest();

		t1 = new OperatorTest();
		t2 = t1;

		result = (t1==t2);

		System.out.println(result);


27.4 算术操作符
	+
		数字之间使用+,表示俩个值相加
		例如:
			int a	 = 1+2;
			double b = 1+2;

			字符之间使用+,表示俩个字符进行编码后的值相加
			char c1 = 'a';//97
			char c2 = 'a';//97
			注意,java中默认采用Unicode编码
			
			int result = c1+c2;

			System.out.println(result);//194


		字符串之间使用+,表示俩个字符串拼接
		注意,也可以使用 +=  操作
		例如:
			String result;
			result = "hello" + " world";

			result += " tom"; // result = result + " tom";
			
			String s1 = "hello";
			String s2 = "\n";
			String s3 = "world";

			result = s1+s2+s3;


			System.out.println(result);


​ 字符串和基本类型数据直接使用+
​ 注意,字符串和任意基本类型数据使用+号操作,最终结果都会变成字符串类型。

​ 例如:
​ String result;

​ byte a1 = 1;
​ short a2 = 2;
​ int a3 = 3;
​ long a4 = 4L;
​ float a5 = 5.0F;
​ double a6 = 6.0D;
​ char a7 = 97;//char a7 = ‘a’;
​ boolean a8 = true;

String str = "hello ";

			result = str + a1;//"hello 1"
			result = str + a2;//"hello 2"
			result = str + a3;//"hello 3"
			result = str + a4;//"hello 4"
			result = str + a5;//"hello 5.0"
			result = str + a6;//"hello 6.0"
			result = str + a7;//"hello a"
			result = str + a8;//"hello true"

			System.out.println(result);


​ 思考1:1 和 “1” 在java中有什么区别?
​ 在没有主动声明数据类型的情况下,1在java中默认是int类型的,而"1"很显然是String类型。
​ 思考2:1 如何转换为 “1” ?
​ int a = 1;
​ String str = a+“”;“1”

​ 思考3:“1” 如何转换为 1 ?
​ int a = Integer.parseInt(“1”);

	-
		两个数字相减
		int a = 1;
		int b = 1;
		int c = a-b;//0
	*
		两个数字相乘
		int a = 1;
		int b = 1;
		int c = a*b;//1

	/
		两个数字相除
		int a = 1;
		int b = 1;
		int c = a/b;//1

		注意,如果俩个数据都是int类型(整型),这里/是整除的意思,就是得到的结果,只要整数部分,不要小数部分。

		int a1 = 5/2;  //2
		int a2 = 10/3; //3
		int a3 = -12/5; //-2
		int a4 = -13/5; //-2

	%
		两个数字取余
		int a = 1;
		int b = 1;
		int c = a%b;//0

	自增和自减操作:++ -- 

	++
		int a = 1;
		a=a+1; 简写为:a+=1; 简写为: a++;
		a+=2; 没有类似的简写


​ 特殊情况:
​ byte a = 1;
​ //编译报错,因为a+1的结果是32位的int
​ a = a+1;

​ byte a = 1;
​ //编译通过
​ a += 1;
​ //编译通过
​ a++;

​ byte a = 127;
​ //编译通过
​ a += 1;// 或者 a++;

//127的byte类型的二进制为:0111 1111
//0111 1111 + 1 = 1000 0000
//1000 000在byte中就表示-128
//其实这个操作,应该是127+1结果是128,然后从byte类型转换为int类型,就是正常的128了,但是由于 += 或 ++ 操作的特殊性,导致加完1之后没有转换类型,结果还是byte,所以就出现了这种情况。
System.out.println(a);//-128


​ ++操作还分俩种情况,一种是在变量前面++,另一种是在变量后面++,
​ 例如: a++ 和 ++a 是有一些区别的

​ a++ 和 ++a 的相同之处:都是让变量a自动加1,也就是自增1

			a++ 和 ++a 的不同之处:	
				a++ 表示先使用a的值,用完了最后在让a自增1。
					先使用、再加1
				++a 表示先让a自增1,然后在使用a的值。
					先加1,再使用
			
			例如:

			int a = 1;
	
			//System.out.println(a++);   //1
			//System.out.println(a);     //2

			System.out.println(++a);   //2
			System.out.println(a);	   //2
				
	--
		a-- 和 --a
		--的相关特点和上面的++是类似的。


27.5 移位操作符

	>>	算术右移位运算,也叫做【带】符号的右移运算
		int a1 = 12 >> 1;

		0000 1100   12
		---------------
		 0000 110   12 >> 1	
		---------------
		00000 110	使用符号位进行补位

		0000 0110   调整下格式  明显结果是6

		注意,这个操作的本质就是除以2^N,这个N就是我们右移的位数。
		注意,除以2^N之后,只保留整数部分
		注意,正数右移之后,最左边空出的位置,都要补0
		注意,负数右移之后,最左边空出的位置,都要补1
	
	<<	左移位运算
		int a1 = 12 << 1;
		
		0000 1100   12
		----------------
		000 1100    12 << 1
		----------------
		000 11000   补位,不分正负数,最右边全补0
		----------------
		0001 1000   调整, 该值为24

		注意,这个操作的本质就是乘以2^N,这个N就是我们左移的位数
		注意,无论正数负数左移之后,最右边空出的位置,都要补0
		注意,当左移之后,得到的数字已经超出当前类型所能表示的最大值的时候,这个值最终会被限定到这个当前类型中,所以最终显示的值会和我们逻辑上算出的值有所不同。
		
		例如:直接使用2进制表示数字
		int a2 = 0b01000000000000000000000000000000;

		int result = a2<<2;//其实这个结果已经超出了int能表示的最大值
	
		System.out.println(result);	//结果是0

		例如:
		long a2 = 0b01000000000000000000000000000000;

		long result = a2<<2;//这个结果还在long能表示的最大值范围内
	
		System.out.println(result);	//结果是4294967296

		注意,特殊情况:
		int a5 = 0b00000000000000000000000000000001;
		
		System.out.println(a5<<32);	//结果是1 相当于1<<0
		System.out.println(a5<<33);	//结果是2 相当于1<<1
		System.out.println(a5<<34);	//结果是4 相当于1<<2
		
		原因:
		如果移动的位数超过了该类型的最大位数,那么编译器会对移动的位数取模/取余。如果对int型移动33位,实际上只移动了33%32=1位。如果对int型移动32位,实际上只移动了32%32=0位


​ >>> 逻辑右移位运算,也叫做【不带】符号的右移运算
​ 注意,这个操作的本质就是除以2^N,这个N就是我们右移的位数。
​ 注意,除以2^N之后,只保留整数部分
​ 注意,正数和负数右移之后,最左边空出的位置,都要补0

​ 例如:
​ int a3 = 12; // 12>>>1 : 6
​ int a4 = -12;//-12>>>1 : 2147483642

​ result = a4>>>1;

System.out.println(result);

	注意:在操作的时候,所使用的都是计算机中的补码

	正数的原码、反码、补码都是一样的
	例如:数字1的原码0000 0001,反码0000 0001,补码0000 0001


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


27.6 位运算操作符
	
	&	与运算
		
		1&1=1, 1&0=0, 0&1=0, 0&0=0

		0000 0111
		&
		0000 0011
		-----------
		0000 0011

	|	或运算
		1|1=1, 1|0=1, 0|1=1, 0|0=0

		0000 0111
		|
		0011 0011
		-----------
		0011 0111

	^	异或运算
		1^1=0, 0^0=0, 1^0=1, 0^1=1
		相同为0,不同为1
		0000 0111
		^
		0000 0011
		-----------
		0000 0100

		运算特征:a^0=a, a^a=0

	~	取反运算
		
		0 -> 1 
		1 -> 0


27.6 逻辑运算操作符

	短路操作符,如果能根据左边第一个布尔表达式的结果能推断出整个表达式的结果,那么后面的布尔表达式就不会被计算了。

		布尔表达式1 && 布尔表达式2 && 布尔表达式3
		布尔表达式1 || 布尔表达式2 || 布尔表达式3


​ && 短路与
​ 例如:
​ int a = 1;
​ int b = 5;

​ boolean result;

​ // a>4 这布尔表达式为false
​ // 后的(b++)>1就不需要计算了
​ // 因为当前是短路与(&&)运算,第一个false已经能够决定整个表达式的结果了
​ // 如果当前是短路或(||)运算,第一个布尔表达式为true才能决定整个表达式的结果
​ result = a>4 && (b++)>1;
​ System.out.println(result);//false
​ System.out.println(b);//输出5

		// 这种情况下,a>0为true
		// 必须要再进行后面表达式的计算,最终才能得到结果
		result = a>0 && (b++)>1;
		System.out.println(result);//true
		System.out.println(b);//输出6

	||	短路或
		||情况和&&情况类似,就是逻辑上有点区别。


​ 思考1: & 和 && 有什么区别
​ &既可以作为二进制数字的位运算符,也可以作为布尔表达式中的逻辑运算符,但是作为逻辑运算符的时候,&并没有&&符合的那种短路的功能。
​ 例如:作为位运算符
​ int a = 1;
​ int b = 1;

​ a&b

​ 0000 0001
​ &
​ 0000 0001
​ ---------
​ 0000 0001

例如:作为逻辑运算符
int a = 1;
int b = 5;

			boolean result;
			result = a>4 & (b++)>1;
			
			注意,这时候,无论任何情况下,都必须算完a>4的结果,和(b++)>1的结果,然后俩个结果在进行&运算,得出最终的结果,也就是这里没有 && 这种短路功能的。


​ && 只能作为逻辑运算符,但是它会具备短路的功能。

​ 注意,&&不能作为二进制数字的位运算符。

​ 思考2: | 和 || 有什么区别
​ 和 & 和 &&的区别类似。

27.7 条件操作符(三目运算符)
	
	变量 = 布尔表达式?值1:值2;
	
	布尔表达式为true时 ,则返回值1
	布尔表达式为false时,则返回值2
	例如:
		int score = 51;
		String result;

		result = (score>=60?"及格":"不及格");
		System.out.println(result);


		//上面代码的效果和这个是一致的
		int score = 51;
		String result;

		if(score>=60){
			result = "及格";
		}else{
			result = "不及格";
		}
		System.out.println(result);
  1. 类型转换

    注意,java中的=号赋值操作,需要=号俩边的类型一致,也就是=号右边的数据的类型要和=号左边的变量的类型保持一致,如果不一致,那么就需要做类型的转换,分为隐式转换和显示转换。

    隐式转换也称为自动转换
    显示转换也称为强制转换

    格式:
    类型名 变量名 = 数据;

    28.1 基本类型之间的转换
    隐式转换(Implicit),也是自动转换,在JVM运行期间,只要满足条件,就可以自动完成类型转换的过程。一般是数据范围比较小的,自动就可以转换为数据范围比较大的类型(基本类型)。

    例如:
    	byte a = 1;
    	int b = a;
    	
    	注意,这里在运行期间,就自动完成了转换的过程
    
    显示转换(explicit),也是手动转换/强制转换,编译器发现类型无法自动转换的情况,就会编译报错,这时候我们确认无误后,就可以进行类型强制转换,但是这里是存在一定风险的,在基本类型数据中,这个风险主要是可能数据有损失,在引用类型中,将来在运行这个类型转换代码的时候,有可能会抛出类型转换异常。
    	
    	例如:
    		int a = 100;
    		//编译报错,因为a是int类型,b是byte
    		//把32位int数据,赋值给8位的变量b
    		//把一个范围大的数据,赋给一个范围小的变量
    		//这时候是不允许的,也无法类型自动转换。
    		byte b = a;
    


​ 例如:
​ int a = 100;
​ //但是我们可以做类型强制转换
​ //对于基本类型,强制转换就是把多余的位给抹去
​ //所以这时候可能对数据的值,造成影响
​ byte b = (byte)a;

		注意,基本类型中的浮点型数据,如果强行转换为整型,那么之前浮点型数据的小数部分,就需要全部抹去。

28.2 引用类型之间的转换

	隐式转换
		例如:
			Student s = new Student();
			Object o = s;

			特点:子类类型的变量,可以自动转为(隐式)父类类型
			
			//上面俩句可以合成这一句代码,其实就是把中间变量s给去掉了。
			Object o = new Student();

			特点:Object是父类型,Student是子类型,父类型的引用o,可以接收/指向 一个子类类型的对象,这是因为在运行期间,=号右边的子类类型Student,可以自动转换为=号左边的Object类型
		
		注意,虽然是引用类型之间的类型转换,但是和基本类型之间的转换还是保持一个规则,就是=号右边小范围类型数据,可以自动转为=号左边大范围类型的数据


	显示转换(类型强制转换,简称强转)

		例如:
			Object o = new Student();

			Student s = (Student)o;

		注意,编译时,编译能不能让这句类型转换的代码编译通过,编译器看的时候,编译器看的=号俩边的的类型是不是一致,或者是不是有子父类的关系,例如:在上面的例子中
			Student s = (Student)o;
		这句代码能不能编译通过,编译器看的是变量o声明的类型是Object,而变量s声明的类型是Student,这俩个类型之间是有子父类关系的,所以编译通过。

		但是在运行时候,JVM能不能成功执行这句代码:
			Student s = (Student)o;
		JVM看的时候变量o在运行的时候,o所指向的对象具体是什么类型的,如果o所指向的对象具体的类型是Student,或者Student类型的子类型,那么这句代码就可以运行成功,否则会报错,错误信息为类型转换异常。


		另外,我们在做类型强制转换的时候,还可以使用instanceof关键字来进行判断,判断的目的是为了看看这个引用o是否真的可以转换为Student类型:
			Object o = new Student();
			if(o instanceof Student){
				Student s = (Student)o;
			}



28.3 类型转换的特点
	
	在java中,一个变量声明之后,它的类型就确定了,并且这个类型是不会改变的,直到这个变量在内存中释放掉。
	int a = 1;
	//使用a的值的时候,由于=号俩边类型不一致,所以需要转换
	//但是这个转换对变量a本身来讲,没有任何影响,在计算机的内存中,只是使用以下a的值,操作完之后的结果,在保存到变量b中,对a本身是没有任何改变和影响的。
	byte b = (byte)a;

	//所以,接下来如果再使用变量a的时候,那么a的类型依然是int,并且a的值依然是1,除非进行了对a赋值操作,否则这值是不会变量的
	//另外,无论对a进行什么操作,变量a的类型一直是int,直到运行结束。
	byte c = (byte)a;
	
	//所以,在下面的代码中,任何地方,如果再使用到变量a,这变量a的类型依然是int


​ //这个引用o在声明的时候是Object类型的
​ //那么在后续的使用中,它将一直是Object类型,不会改变。
​ Object o = new Student();

​ Student s = (Student)o;

  1. 流程控制

    29.1 if语句

    if(布尔表达式){
    	//if中需要执行的代码
    }
    
    注意,if中的代码是否执行,主要是看这里的布尔表达式的结果,如果是true则执行代码,如果是false则不执行。
    
    例如:
    	int a = 10;
    	if(a%2==0){
    		System.out.println("变量a的值为偶数");
    	}
    

    29.2 if-else语句
    if(布尔表达式){
    //if中需要执行的代码
    }
    else{
    //else中需要执行的代码
    }

    注意,if和else形成了一个组合,特点就是如果if中的代码执行了,那么else的代码就不执行,如果if中的代码没执行,那么else中的代码就会执行。也就是if和else这俩个语句中的代码,【一定】是有唯一的一个执行,而另一个不执行。
    
    例如:
    	int a = 10;
    	if(a%2==0){
    		System.out.println("变量a的值为偶数");
    	}
    	else{
    		System.out.println("变量a的值为奇数");
    	}
    
    
    例如:俩个if的情况
    	int a = 10;
    	if(a%2==0){
    		System.out.println("变量a的值为偶数");
    	}
    	if(a%2==1){
    		System.out.println("变量a的值为奇数");
    	}
    
    	注意,这种情况,逻辑上和if-else组合是不同的,if-else组合是代码二选一,一定会【有且只有】一个执行,但是这个例子中的俩个if语言,那么会依次使用变量a,分别在俩个if中做判断。
    	第一个if条件成立了,那么就执行代码,如果不成立就算了,接着继续判断第二个if的条件,如果条件成立了,那么就执行代码,如果不成立就算了。
    	也就是无论什么情况,俩个if都会依次做出条件判断。
    

    29.3 if-elseif语句

    if(布尔表达式){
    	//if中需要执行的代码
    }
    else if(布尔表达式){
    	//else-if中需要执行的代码
    }
    else if(布尔表达式){
    	//else-if中需要执行的代码
    }
    ...
    
    注意,if和else-if搭配形成一个组合,这里面的else-if可以出现多次。
    
    特点:把条件安装if + else-if 的编写顺序,依次做出判断,然后其中有一个判断成立的,返回true,那么下面的其他判断就不在进行。在这个组合中,只能会有一个判断执行,任意一个执行后其他都不在判断了。当然也有可能所以判断都不成立,都是返回的false,那么这个所以代码都不会执行了。
    例如:
    	int a = 10;
    	if(a%2==0){
    		System.out.println("变量a的值为偶数");
    	}
    	else if(a%2==1){
    		System.out.println("变量a的值为奇数");
    	}
    

    29.4 if-elseif-else语句

    if(布尔表达式){
    	//if中需要执行的代码
    }
    else if(布尔表达式){
    	//else-if中需要执行的代码
    }
    else if(布尔表达式){
    	//else-if中需要执行的代码
    }
    ...
    else{
    	//else中需要执行的代码
    }
    
    特点:如果前面的所有判断都不成立,那么最后一定会执行else中的代码
    

    29.5 if语句的简写形式

    例如:
    	int a = (int)(Math.random()*100);
    	if(a%5==0){
    		System.out.println("余数为0");
    	}
    	else if(a%5==1){
    		System.out.println("余数为1");
    	}	 
    	else if(a%5==2){
    		System.out.println("余数为2");
    	}	 
    	else if(a%5==3){
    		System.out.println("余数为3");
    	}
    	else{
    		System.out.println("余数为4");
    	}
    	
    	可以简写为:
    
    	int a = (int)(Math.random()*100);
    	if(a%5==0) System.out.println("余数为0");
    
    	else if(a%5==1) System.out.println("余数为1");
    	
    	else if(a%5==2) System.out.println("余数为2");
    
    	else if(a%5==3) System.out.println("余数为3");
    
    	else System.out.println("余数为4");
    
    
    	规则:如果if、else-if、else语句中要执行的代码只有一句,那么可以把外面的大括号省去不写。
    

    29.6 if相关示例
    实现一个方法,方法调用完后会返回一个问候的语句,例如如果是8点12点之间,那么就返回早上好,如果是12点14点,则返回中午好,如果是14点-18点,则返回下午好,其他情况,返回晚上好。

    	public String sayHello(int hour){
    		String message;
    		
    		if(hour>=8 && hour<12){
    			message = "早上好";
    		}
    		else if(hour>=12 && hour<14){
    			message = "中午好";
    		}
    		else if(hour>=14 && hour<18){
    			message = "下午好";
    		}
    		else{
    			message = "晚上好";
    		}
    
    		return message;
    	}
    


​ 实现一个方法,方法需要传一个参数,表示年份,方法调用完后会返回一个boolean值,表示这个年份是不是闰年

​ 闰年判断标准:以下条件满足一个,就是闰年
​ 1.能被4整除,但是不能被100整除
​ 2.能被400整除

		public boolean isLeapYear(int year){
			boolean flag = false;
			
			if((year%4==0 && year%100!=0) || year%400==0){
				flag = true;
			}

			return flag;
		}



29.7 switch-case语句
	格式:
		switch(var){
			
			case 值1:{
				code1;
				break;
			}

			case 值2:{
				code1;
				break;
			}

			case 值3:{
				code1;
				break;
			}

			default:{
				code1;
			}
		}


​ 注意,这里的break关键字,表示退出switch代码
​ 注意,这里对比的变量var的类型是有要求的,必须是byte、short、int、char这四种,JDK8中也允许String类型的变量做对比。
​ 注意,使用switch来完成的功能,同样可以使用if来完成,但是使用if完成的功能,使用switch不一定能完成。


​ 例如:
​ int mode = 0;//0 1 2 3

​ switch(mode){

​ case 0:{

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值