java基础篇章1
1.1 java三种平台
Java语言:完全面向对象(java语言底层实际上是C++实现的。)
Java被分为三大块:
J2SE:标准版(基础,要学java,必须先学习SE。基础
语法+基础库)
J2EE:企业版(专门为企业开发软件,为企业提供解决方案。
例如:OA办公系统,保险行业的系统,金融行业的系统,
医院系统....)
J2ME:微型版(专门为微型设备做嵌入式开发的。)
1.2 JDK、JRE、JVM三者之间的关系?
JDK:Java开发工具箱
JRE:Java运行环境
JVM:Java虚拟机
JDK包括JRE,JRE包括JVM
JVM是不能独立安装的。JDK和JRE都是可以独立安装的。
安装JDK的时候:JRE就自动安装了,同时JRE内部的JVM
也就自动安装了。
1.3 如河查看版本信息
javac -version(查看编译器版本)
java -version(查看java虚拟机的版本)
1.4 Java的三个步骤
编写/编译/解释,编译期间检查Java语法,如果出现错误,则
不会产生类文件,
解释期间则将类文件装进JVM中,解释成二进制文件,然
后机器才能识别运行.
1.5 如河运次java文件
javac 绝对路径或相对路径
java 类名
例子:比如有一个aa.java存在于C:/downloads/aa.java,则
编译为javac C:/downloads/aa.java,或者为相对路径.
解释为java aa,记住,必须切换到类文件的所在目录,不可以跟路径
1.6 java的配置
path:需要配置到java,javac所在的目录,即为路径名/bin
补充:windows操作系统是如何搜索硬盘上某个命令的呢?
首先会从当前目录下搜索,当前目录搜索不到的话,会从环境变量path
指定的路径当中搜索某个命令,如果还找不到则报错
1.7 "java HelloWorld"的执行过程以及原理。
D:\course\JavaProjects\02-JavaSE\chapter01>java HelloWorld
敲完回车,都发生了什么?????
第一步:会先启动JVM(java虚拟机)
第二步:JVM启动之后,JVM会去启动“类加载器classloader”
类加载器的作用:加载类的。本质上类加载器负责去硬盘上
找“类”对应的“字节码”文件。
假设是“java HelloWorld”,那么类加载器会去硬盘上
搜索:HelloWorld.class文件。
假设是“java Test”,那么类加载器会去硬盘上搜
索:Test.class文件。
.......
第三步:
类加载器如果在硬盘上找不到对应的字节码文件,会报错,报什么错?
错误: 找不到或无法加载主类
类加载器如果在硬盘上找到了对应的字节码文件,类加载
器会将该字节码
文件装载到JVM当中,JVM启动“解释器”将字节码
解释为“101010000...”这种
二进制码,操作系统执行二进制码和硬件交互。
问题?????
默认情况下,类加载器去硬盘上找“字节码”文件的时候,
默认从哪找????
默认情况下类加载器(classloader)会从当前路径下找。
此处应该有疑问,你可以提出哪些问题????
能不能给类加载器指定一个路径,让类加载器去指定的
路径下加载字节码文件。
答案:可以的。但是我们需要设置一个环境变量,叫做:classpath
classpath是一个环境变量,是给谁指路的?
答案:是给“类加载器”指路的。
classpath环境变量不属于windows操作系统,
classpath环境变量隶属于java。
你一定要理解classpath环境变量的作用是什么?
是给类加载器指路的。
在没有配置环境变量classpath的时候,默认从当前路径下加载。
如果配置了环境变量classpath的话,就只能从指定的路径下加载了。
path JAVA_HOME classpath,这3个环境变量path需要
配置,后面两个暂时不配置。
1.8 关于C与Java的不同
Java没有无符号的byte,short,int和long,这一点
和C语言有很大的
不同。因此unsigned int m是错误的变量声明
与C不同,Java不允许在声明数组中的方括号内指定
数组元素,如int a[12];
与C不同,Java允许数组元素的个数为int型变量。如
int size=10; double number[]=new double[size];
与C不同,Java允许二维数组的列元素的个数可以不相同
1.9 Java的三种注释
// 单行注释
/*
多行注释
*/
/**
* javadoc注释:这里的注释信息可以自动被javadoc.exe
* 命令解析提取并生成到帮助文档当中。
*/
1.10 标识符
规则1:标识符只能由数字、字母(包括中文)、下划线_、美
元符号$组成,
不能含有其它符号。
规则2:标识符不能以数字开头
规则3:关键字不能做标识符。
例如:public class static void 这些蓝色的字体
都是关键字,关键字是不能做标识符的。
规则4:标识符是严格区分大小写的。大写A和小写a不一样。
规则5:标识符理论上是没有长度限制的。
1.10.1 标识符命名规范
具体的命名规范是哪些?
规范1:见名知意(这个标识符在起名的时候,最好
一看这个单词就知道啥意思。)
规范2:遵循驼峰命名方式,什么是驼峰(一高一低,一高一低...)
驼峰有利于单词与单词之间很好的进行分隔
BiaoShiFuTest,这个很好,一眼就能看出来是4个单词。
规范3:类名、接口名有特殊要求
类名和接口名首字母大写,后面每个单词首字母大写。
StudentTest、UserTest ,这是类名、接口名。
规范4:变量名、方法名有特殊要求
变量名和方法名首字母小写,后面每个单词首字母大写。
nianLing(NianLing这样就不符合了。)
mingZi(MingZi这样也不符合了。)
规范5:所有“常量”名:全部大写,并且单词和单词
之间采用下划线衔接。
USER_AGE :用户年龄
MATH_PI:固定不变的常量3.1415926.....
1.11 关键字
在SUN公司开发Java语言的时候,提前定义好了一些具
有特殊含义的单词,
这些单词全部小写,具有特殊含义,不能用作标识符。比如:
关键字:
public
static
void
class
byte
short
int
long
float
double
boolean
char
true
false
if
while
for
private
protected
........
1.12 字面量
字面量就是数据
10 100 123 :整型
1.34 3.14 2.0:浮点型
true false :布尔型
'a' '国':字符型
"a" "abc" "国" "中国":字符串型
10:整数,是一个数字
"10":它不是数字,是一个字符串,或者说,它属于“文字类”的。
性质完全不同,在计算机中的对应的二进制码也是完全不同的。
1.13 变量
java中的变量必须先声明,再赋值才能访问(必须手动赋值。)
int k; System.out.println(k); 这样是不行的.
1 关于变量的一个分类(这个需要“死记硬背”。)
变量根据出现的位置进行划分:
在方法体当中声明的变量:局部变量。
在方法体之外,类体内声明的变量:成员变量。
2 注意:局部变量只在方法体当中有效,方法体执行结束该
变量的内存就释放了。
1.14 public class 跟 class的区别:
1 一个java源文件当中可以定义多个class.
2 一个java源文件当中public的class不是必须的.
3 一个class会定义生成一个xxx.class字节码文件.
4 一个java源文件当中定义公开的类的话,只能有
一个,并且该类名称必须和java源文件名称一致.
5 每一个class当中都可以编写main方法,都可以
设定程序的入口,想执行B.class中的main方法:java B,
想执行X.class当中的main方法:java X.
注意:当在命令窗口中执行java Hello,那么要求Hello.class
当中必须要有主方法.没有主方法会出现运行阶段的错误.
面试题
一个".java"源文件中是否可以包括多个类(不是内部类)?有
什么限制?
可以有多个类,但只能有一个 public 的类,并且 public 的类名
必须与文件名相一致。
1.15 数据类型
java中规定,任何一个浮点型数据默认被当做double来处理。
在任何情况下,整数型的“字面量/数据”默认被当做int类型处理。
第一种:基本数据类型
基本数据类型又可以划分为4大类8小种:
第一类:整数型
byte,short,int,long (没有小数的)
第二类:浮点型
float,double (带有小数的)
第三类:布尔型
boolean:只有两个值true和false,true表示真,false表示假
第四类:字符型
char:java中规定字符型字面量必须使用单引号括起来。属于文字。
8小种:
byte,short,int,long
float,double
boolean
char
第二种:引用数据类型
字符串型String属于引用数据类型。
String字符串不属于基本数据类型范畴。
java中除了基本数据类型之外,剩下的都是引用数据类型。
类型 占用字节数量(byte)
------------------------------------
byte 1
short 2
int 4
long 8
float 4
double 8
boolean 1 (1byte的1或0,00000001(true)或00000000(false))
char 2
1.16 八种基本数据类型详解
1 关于数据类型详解
字符型:char
整数型:byte short int long
在java中有一条非常重要的结论,必须记住:
在任何情况下,整数型的“字面量/数据”默认被当做int类型处理。
第一个结论:当一个整数赋值给char类型变量的时候,会自
动转换成char字符型,
最终的结果是一个字符。
第二个结论:当一个整数没有超出byte short char的取值范
围的时候,
这个整数可以直接赋值给byte short char类型的变量。
浮点型:float double
关于java语言中的浮点型数据
如果用在银行方面或者说使用在财务方面,double
也是远远不够的,在java中提供了一种精度更高的类型,
这种类型专门
使用在财务软件方面:java.math.BigDecimal
(不是基本数据类型,属于
引用数据类型。)
类型转换
1 小容量可以直接赋值给大容量,称为自动类型转换。
2 大容量不能直接赋值给小容量,需要使用强制类型转换符进行强转。
大容量转换成小容量,要想编译通过,必须加强制类型转换符,
进行强制类型转换。
底层是怎么进行强制类型转换的呢?
long类型100L:00000000 00000000 00000000 00000000 00000000 00000000 00000000 01100100
以上的long类型100L强转为int类型,会自动将“前面”的4个字节砍掉:00000000 00000000 00000000 01100100
但需要注意的是:加强制类型转换符之后,虽然编译通过了,但是运行
的时候可能会损失精度。
2 综合的看一下,在类型转换的时候需要遵循哪些规则?(笔试题)
第一条:八种基本数据类型中,除 boolean 类型不能转换,剩下七种类型之间都可以
进行转换;
第二条:如果整数型字面量没有超出 byte,short,char 的取值范围,可以直接将其赋
值给byte,short,char 类型的变量;
第三条:小容量向大容量转换称为自动类型转换,容量从小到大的排序为:
byte < short(char) < int < long < float < double,其中 short和 char
都占用两个字节,但是char 可以表示更大的正整数;
第四条:大容量转换成小容量,称为强制类型转换,编写时必须添加“强制类型转换符”,
但运行时可能出现精度损失,谨慎使用;
第五条:byte,short,char 类型混合运算时,先各自转换成 int 类型再做运算;
第六条:多种数据类型混合运算,各自先转换成容量最大的那一种再做运算;
其中第五条不符合这个规则(例外)。
例子1:
char c1 = 'a';
byte b = 1;
short s = c1 + b; // 编译器不知道这个加法最后的结果是多少。只知道是int类型。
解析:c1先转换成int类型,b先转换成int类型,然后两者合起来是int类型,无法编译通过。
例子2:
long a = 10L;
char c = 'a';
short s = 100;
int i = 30;
// 错误: 不兼容的类型: 从long转换到int可能会有损失
int x = a + c + s + i; // 计算结果是long类型
解析:c、s、i各自转换为容量最大的long类型,然后参与运算,结果是long类型,编译不通过。需改成
int x = (int)(a + c + s + i);
注意:java中规定,int类型和int类型最终的结果还是int类型。
int temp = 10 / 3; // 结果是:3
int temp2 = 1 / 2;结果是:0
练习题:
byte b1 = 1000; // 编译报错,因为1000已经超出范围了。
byte b2 = 20; // 可以
short s = 1000; // 可以
int c = 1000; // 可以
long d = c; // 可以
int e = d; // 编译报错
int f = 10 / 3; // 可以
long g = 10; // 可以
int h = g / 3; // 编译报错
long m = g / 3; // 可以
byte x = (byte)g / 3; // 编译报错
short y = (short)(g / 3); // 可以
short i = 10; // 可以
byte j = 5; // 可以
short k = i + j; // 编译报错
int n = i + j; // 可以
char cc = 'a'; // 可以
int o = cc + 100; // 197,cc 会先自动转换成int类型,再做运算
2.1 运算符
算术运算符:
+求和 -相减 * 乘积 /商 %求余数(求模) ++自加1 --自减1
对于++运算符来说:
可以出现在变量前,也可以出现在变量后。
不管出现在变量前还是后,总之++执行结束之后,变量的值一定会自加1。
关系运算符:
> >= < <= == !=
一定要记住一个规则:
所有的关系运算符的运算结果都是布尔类型,
不是true就是false,不可能是其他值。
在java语言中:
= : 赋值运算符
== :关系运算符,判断是否相等。
*/
逻辑运算符:
& 逻辑与(可以翻译成并且)
| 逻辑或(可以翻译成或者)
! 逻辑非(取反)
&& 短路与
|| 短路或
重点短路与&& 和 逻辑与 &有什么区别?
首先这两个运算符的运算结果没有任何区别,完全相同。
只不过“短路与&&”会发生短路现象。
什么是短路现象呢?
右边表达式不执行,这种现象叫做短路现象。
什么时候使用&&,什么时候使用& ?
从效率方面来说,&&比&的效率高一些。
因为逻辑与&不管第一个表达式结果是什么,第二个表达式一定会执行。
以后的开发中,短路与&&和逻辑与还是需要同时并存的。
大部分情况下都建议使用短路与&&
只有当既需要左边表达式执行,又需要右边表达式执行的时候,才会
选择逻辑与&。
问题:重点短路或||和 逻辑或|有什么区别?
短路或||会发生短路,即当左边的表达式结果是true的时候,右边的表达式不需要执行,此时会短路。
赋值运算符:
1、赋值运算符包括“基本赋值运算符”和“扩展赋值运算符”:基本的、扩展的。
2、基本赋值运算符?
=
3、扩展的赋值运算符?
+= -= *= /= %=
4、很重要的语法机制:
使用扩展赋值运算符的时候,永远都不会改变运算结果类型。
byte x = 100;
x += 1;
x自诞生以来是byte类型,那么x变量的类型永远都是byte。不会变。不管后面是多大的数字.
例子:
int i = 10;
研究:
i += 10 和 i = i + 10 真的是完全一样吗?
答案:不一样,只能说相似,其实本质上并不是完全相同。
i += 10 等同于:i = (int)(i + 1);
解析:第一种因为是i是int类型,所以后面无论与什么类型的数参与运算,其类型不会变.
第二种就会变,符合前面提到的规则.
三目运算符(条件运算符):
布尔表达式 ? 表达式1 : 表达式2
执行原理是什么?
布尔表达式的结果为true时,表达式1的执行结果作为整个表达式的结果。
布尔表达式的结果为false时,表达式2的执行结果作为整个表达式的结果。
字符串连接运算符:
+ 运算符:
1、+ 运算符在java语言中有两个作用。
作用1:求和
作用2:字符串拼接
2、什么时候求和?什么时候进行字符串的拼接呢?
当 + 运算符两边都是数字类型的时候,求和。
当 + 运算符两边的“任意一边”是字符串类型,那么这个+会进行字符串拼接操作。
3、一定要记住:字符串拼接完之后的结果还是一个字符串。
面试题
1.8 用最有效率的方法算出 2 乘以 8 等于几?
2 << 3,
因为将一个数左移 n 位,就相当于乘以了 2 的 n 次方,那么,一个数乘以 8 只要
将其左移 3 位即可,而位运算 cpu 直接支持的,效率最高,所以,2 乘以 8 等于
几的最效率的方法是 2 << 3。
2.2 控制语句
选择语句/循环语句/转向语句
2.2.1 选择语句(分支语句)
if语句
switch语句
2.2.1.1 if语句
第一种写法:
int a = 100;
int b = 200;
if(布尔表达式){
java语句;
java语句;
}
第二种写法:
if(布尔表达式){
java语句;
}else{
java语句;
}
if(布尔表达式1){
java语句;
}else if(布尔表达式2){
java语句;
}else if(布尔表达式3){
java语句;
}else if(布尔表达式4){
java语句;
}....
第四种写法:
if(布尔表达式1){
java语句;
}else if(布尔表达式2){
java语句;
}else if(布尔表达式3){
java语句;
}else if(布尔表达式4){
java语句;
}else{
java语句;
}
注意:
1、对于if语句来说,在任何情况下只能有1个分支执行,不可能
存在2个或者更多个分支执行。if语句中只要有1个分支执行了,
整个if语句就结束了。(对于1个完整的if语句来说的。)
2、以上4种语法机制中,凡是带有else分支的,一定可以保证会有
一个分支执行。以上4种当中,第一种和第三种没有else分支,这样
的语句可能会导致最后一个分支都不执行。第二种和第四种肯定会有
1个分支执行。
3、当分支当中“java语句;”只有1条,那么大括号{}可以省略,但为了可读性,最好不要省略。
2.2.1.2 switch语句
switch(值){
case 值1:
java语句;
java语句;...
break;
case 值2:
java语句;
java语句;...
break;
case 值3:
java语句;
java语句;...
break;
default:
java语句;
}
以上是一个完整的switch语句:
其中:break;语句不是必须的。default分支也不是必须的。
switch语句支持的值有哪些?
支持int类型以及String类型。
但一定要注意JDK的版本,JDK8之前不支持String类型,只支持int。
在JDK8之后,switch语句开始支持字符串String类型。
// 分析这个程序是否能够编译通过?
// switch只支持int和String类型。
// 错误: 不兼容的类型: 从long转换到int可能会有损失
long x = 100L;
switch(x){
}
switch语句本质上是只支持int和String,但是byte,short,char也可以
使用在switch语句当中,因为byte short char可以进行自动类
型转换,转换为int类型。
switch语句中“值”与“值1”、“值2”比较的时候会使用“==”进行比较。
switch语句的执行原理
拿“值”与“值1”进行比较,如果相同,则执行该分支中的java语句,
然后遇到"break;"语句,switch语句就结束了。
如果“值”与“值1”不相等,会继续拿“值”与“值2”进行比较,如果相同,
则执行该分支中的java语句,然后遇到break;语句,switch结束。
注意:如果分支执行了,但是分支最后没有“break;”,此时会发生case
穿透现象。
所有的case都没有匹配成功,那么最后default分支会执行。
2.2.2 循环语句
for循环
while循环
do..while..循环
2.2.2.1 for循环
for(初始化表达式; 条件表达式; 更新表达式){
循环体; // 循环体由java语句构成
java语句;
java语句;
java语句;
java语句;
....
}
注意:
第一:初始化表达式最先执行,并且在整个循环中只执行一次。
第二:条件表达式结果必须是一个布尔类型,也就是:true或false
执行原理:
先执行初始化表达式,并且初始化表达式只执行1次。
然后判断条件表达式的结果,如果条件表达式结果为true,
则执行循环体。
循环体结束之后,执行更新表达式。
更新完之后,再判断条件表达式的结果,
如果还是true,继续执行循环体。
直到更新表达式执行结束之后,再次判断条件时,条件为false,
for循环终止。
2.2.2.2 while语句
while(布尔表达式){
循环体;
}
执行原理:
判断布尔表达式的结果,如果为true就执行循环体,
循环体结束之后,再次判断布尔表达式的结果,如果
还是true,继续执行循环体,直到布尔表达式结果
为false,while循环结束。
2.2.2.3 do…while…循环
do {
循环体;
}while(布尔表达式);
注意:do..while循环最后的时候别漏掉“分号”
执行原理:
先执行循环体当中的代码,执行一次循环体之后,
判断布尔表达式的结果,如果为true,则继续执行
循环体,如果为false循环结束。
对于do..while循环来说,循环体至少执行1次。循环体的执行次
数是:1~n次。
对于while循环来说,循环体执行次数是:0~n次。
public class test {
public static void main(String[] args) {
int arr[][] = {{1,2,3},{4,5,6,7},{9}};
boolean found = false;
for(int i=0;i<arr.length && !found;i++){
for(int j=0;j<arr[i].length;j++){
System.out.println("i=" + i +","+ "j=" + j);
if(arr[i][j] == 5){
found = true;
break;
}
}
}
}
}
2.2.3 转向语句
break
continue
return
2.2.3.1 break
第一个位置:switch语句当中,用来终止switch语句的执行。
用在switch语句当中,防止case穿透现象,用来终止switch。
第二个位置:break;语句用在循环语句当中,用来终止循环的执行。
用在for当中
用在while当中
用在do....while..当中。
break;语句的执行并不会让整个方法结束,break;语句主要是用
来终止离它最近
的那个循环语句。
for(int i = 0; i < 10; i++){
if(i == 5){
// break;语句会让离它最近的循环终止结束掉。
break; // break;终止的不是if,不是针对if的,而是针对离它最近的循环。
}
System.out.println("i = " + i); // 0 1 2 3 4
}
2.2.3.2 continue
终止当前"本次"循环,直接进入下一次循环继续执行。
for(){
if(){ // 当这个条件成立时,执行continue语句
continue; //当这个continue语句执行时,continue下面的代码不执行,直接进入下一次循环执行。
}
// 以上的continue一旦执行,以下代码不执行,直接执行更新表达式。
code1;
code2;
code3;
code4;
}
3.1 方法
1 方法怎么定义,语法机制是什么?
[修饰符列表] 返回值类型 方法名(形式参数列表){
方法体;
}
返回值类型
第一:当一个方法执行结束不返回任何值的时候,返回值
类型也不能空白,必须写上void关键字。所以void表示该
方法执行结束后不返回任何结果。
第二:如果返回值类型“不是void”,那么你在方法体执行结
束的时候必须使用
"return 值;"这样的语句来完成“值”的返回,如果没有“return 值;”这样
的语句
那么编译器会报错。
return 值; 这样的语句作用是什么?作用是“返回值”,返回方法的执行结果。
第三:只要有“return”关键字的语句执行,当前方法必然结束。
return只要执行,当前所在的方法结束,记住:不是整个程序结束。
第四:如果返回值类型是void,那么在方法体当中不能有“return 值;”这样的
语句。但是可以有“return;”语句。这个语句“return;”的作用就是用来终止当前
方法的。
public static void divide(int a, int b){
return; // 用来终止这个方法的
}
第五:除了void之外,剩下的都必须有“return 值;”这样的语句。
方法名
1 方法名要见名知意。(驼峰命名方式)
方法名在标识符命名规范当中,要求首字母小写,后面每个单词首字母大写。
只要是合法的标识符就行。
2 形式参数列表
简称:形参
注意:形式参数列表中的每一个参数都是“局部变量”,方法结束之后内存释放。
形参的个数是:0~N个。
形参有多个的话使用“逗号,”隔开。逗号是英文的。
形参的数据类型起决定性作用,形参对应的变量名是随意的。
方法体:
由Java语句构成。java语句以“;”结尾。
注意:
1 在方法调用的时候,什么时候“类名.”是可以省略的。什么时候不能省略?
a()方法调用b()方法的时候,a和b方法都在同一个类中,“类名.”可以
省略。如果不在同一个类中“类名.”不能省略。
2 break;语句和return;语句有什么区别?
不是一个级别。
break;用来终止switch和离它最近的循环。
return;用来终止离它最近的一个方法。
3.1.1 方法重载
什么时候代码会发生方法重载?
条件1:在同一个类当中
条件2:方法名相同
条件3:参数列表不同
参数的个数不同算不同
参数的类型不同算不同
参数的顺序不同算不同
只要同时满足以上3个条件,那么我们可以认定方法和方法之间发生了
重载机制。
方法重载和方法的“返回值类型”无关。
方法重载和方法的“修饰符列表”无关。
在java语言中,是怎么进行方法区分的呢?
首先java编译器会通过方法名进行区分。
但是在java语言中允许方法名相同的情况出现。
如果方法名相同的情况下,编译器会通过方法的参数类型进
行方法的区分。
public class OverloadTest03{
public static void main(String[] args){
m1();
m1(100);
m2(10, 3.14);
m2(3.14, 10);
m3(100);
m3(3.14);
}
public static void m1(){
System.out.println("m1无参数的执行!");
}
public static void m1(int a){
System.out.println("m1有一个int参数执行!");
}
public static void m2(int x, double y){
System.out.println("m2(int x, double y)");
}
public static void m2(double y, int x){
System.out.println("m2(double y, int x)");
}
public static void m3(int x){
System.out.println("m3(int x)");
}
public static void m3(double d){
System.out.println("m3(double d)");
}
}
class MyClass{
public static void m1(int x, int y){
}
}
3.1.2 方法递归
方法递归?
1 什么是方法递归?
方法自己调用自己,这就是方法递归。
2 当递归时程序没有结束条件,一定会发生:
栈内存溢出错误:StackOverflowError
所以:递归必须要有结束条件。
JVM发生错误之后只有一个结果,就是退出JVM。
3 递归假设是有结束条件的,就一定不会发生栈内存溢出错误吗?
假设这个结束条件是对的,是合法的,递归有的时候也会出现
栈内存溢出错误。
因为有可能递归的太深,栈内存不够了。因为一直在压栈。
4 在实际的开发中,不建议轻易的选择递归,能用for循环while循
环代替的,尽量使用循环来做。因为循环的效率高,耗费的内存少。
递归耗费的内存比较大,另外递归的使用不当,会导致JVM死掉。
5 在实际的开发中,假设有一天你真正的遇到了:StackOverflowError
你怎么解决这个问题,可以谈一下你的思路吗?
我来谈一下我的个人思路:
首先第一步:
先检查递归的结束条件对不对。如果递归结束条件不对,
必须对条件进一步修改,直到正确为止。
第二步:假设递归条件没问题,怎么办?
这个时候需要手动的调整JVM的栈内存初始化大小。
可以将栈内存的空间调大点。(可以调整大一些。)
第三步:调整了大小,如果运行时还是出现这个错误,
没办法,只能继续扩大栈的内存大小。
(java -X)这个可以查看调整堆栈大小的参数
public class RecursionTest04{
public static void main(String[] args){
int n = 5;
int jieGuo = jieCheng(n);
System.out.println(jieGuo);
System.out.println(jieCheng2(5));
}
public static int jieCheng2(int n){
int result = 1;
for(int i = 2; i <= n; i++){
result *= i;
}
return result;
}
public static int jieCheng(int n){
if(n == 1){
return 1;
}
return n * jieCheng(n - 1);
}
}
4.1 类跟对象
1 当我们采用面向对象的方式贯穿整个系统的话,涉及到三个术语:
OOA:面向对象分析
OOD:面向对象设计
OOP:面向对象编程
整个软件开发的过程,都是采用OO进行贯穿的。
实现一个软件的过程:
分析(A) --> 设计(D) --> 编程(P)
2 面向对象包括三大特征
封装
继承
多态
3 什么是类?
类就是一个模板:类中描述的是所有对象的“共同特征信息”
对象就是通过类创建出的个体。
这几个术语你需要自己能够阐述出来:
类:不存在的,人类大脑思考总结一个模板(这个模板当中描
述了共同特征。)
对象:实际存在的个体。
实例:对象还有另一个名字叫做实例。
实例化:通过类这个模板创建对象的过程,叫做:实例化。
抽象:多个对象具有共同特征,进行思考总结抽取共同特征的过程。
类 --【实例化】--> 对象(实例)
对象 --【抽象】--> 类
类的定义
[修饰符列表] class 类名 {
//类体 = 属性 + 方法
// 属性在代码上以“变量”的形式存在(描述状态)
// 方法描述动作/行为
}
注意:修饰符列表可以省略。
4 关于编译的过程
按说应该先编译XueSheng.java,然后再编译XueShengTest.java
但是对于编译器来说,编译XueShengTest.java文件的时候,会自动
找XueSheng.class.
第一种方式:
javac XueSheng.java
javac XueShengTest.java
第二种方式:
javac XueShengTest.java
第三种方式:
javac *.java
5 在语法级别上是怎么完成对象创建的呢?
类名 变量名 = new 类名();
这样就完成了对象的创建。
6 什么是实例变量?
对象又被称为实例。
实例变量实际上就是:对象级别的变量,也叫成员变量。
注意:对于成员变量来说,没有手动赋值时,系统默认赋值。
类型 默认值
---------------------
byte 0
short 0
int 0
long 0L
float 0.0F
double 0.0
boolean false
char \u0000
引用数据类型 null
null是一个java关键字,全部小写,表示空。是引用类型的默认值。
7、对象和引用的区别?
对象是通过new出来的,在堆内存中存储。
引用是:是变量,并且该变量中保存了内存地址指向了堆内存当中
的对象的。
4.1.1 构造方法
1、什么是构造方法,有什么用?
构造方法是一个比较特殊的方法,通过构造方法可以完成对象的创建,
以及实例变量的初始化。换句话说:构造方法是用来创建对象,并且
同时给对象的属性赋值。(注意:实例变量没有手动赋值的时候,系统
会赋默认值。)
2、重点(需要记忆):当一个类没有提供任何构造方法,系统会默认提供
一个无参数的构造方法。(而这个构造方法被称为缺省构造器。)
3、调用构造方法怎么调用呢?
使用哪个运算符呢?
使用new运算符来调用构造方法。
语法格式:
new 构造方法名(实际参数列表);
4、构造方法的语法结构是?
[修饰符列表] 构造方法名(形式参数列表){
构造方法体;
通常在构造方法体当中给属性赋值,完成属性的初始化。
}
注意:
第一:构造方法名和类名必须一致。
第三:构造方法不需要指定返回值类型,也不能写void,写上void
表示普通方法,就不是构造方法了。
5.构造方法支持方法重载吗?
构造方法是支持方法重载的。
在一个类当中构造方法可以有多个。
并且所有的构造方法名字都是一样的。
6.实例变量在类加载是初始化吗?实例变量在什么时候初始化?
不是,实例变量是在构造方法执行的过程中完成初始化的,完成
赋值的。
public class ConstructorTest01{
public static void main(String[] args){
new Student();
ConstructorTest01.doSome();
doSome();
Student s1 = new Student();
System.out.println(s1);
Student s3 = new Student(100);
System.out.println(s3);
}
public static void doSome(){
System.out.println("do some!!!!");
}
}
4.1.2 封装
1 封装的代码实现两步:
第一步:属性私有化
第二步:1个属性对外提供两个set和get方法。外部程序只能
通过set方法修改,只能通过get方法读取,
可以在set方法中设立关卡来保证数据的安全性。
在强调一下:
set和get方法都是实例方法,不能带static。
不带static的方法称为实例方法,实例方法的调用必须先new对象。
set和get方法写的时候有严格的规范要求:(大家要按照规矩来)
set方法长这个样子:
public void set+属性名首字母大写(1个参数){
xxx = 1个参数;
}
get方法长这个样子:
public 返回值类型 get+属性名首字母大写(无参){
return xxx;
}
public class Person{
private int age;
public int getAge(){
return age;
}
public void setAge(int nianLing){
if(nianLing < 0 || nianLing > 150){
System.out.println("对不起,年龄值不合法,请重新赋值!");
return;
}
age = nianLing;
}
}
4.1.3 static关键字
1 static翻译为“静态”
2 所有static关键字修饰的都是类相关的,类级别的。
3 所有static修饰的,都是采用“类名.”的方式访问。
4 static修饰的变量:静态变量
5 static修饰的方法:静态方法
变量的分类:
变量根据声明的位置进行划分:
在方法体当中声明的变量叫做:局部变量。
在方法体外声明的变量叫做:成员变量。
成员变量又可以分为:
实例变量
静态变量
什么时候变量声明为实例的,什么时候声明为静态的?
如果这个类型的所有对象的某个属性值都是一样的,
不建议定义为实例变量,浪费内存空间。建议定义
为类级别特征,定义为静态变量,在方法区中只保留
一份,节省内存开销。
4.1.4 静态代码块(特殊的时机:类加载时机。)
static {
java语句;
java语句;
}
1 static静态代码块在什么时候执行呢?
类加载时执行。并且只执行一次。
注意:静态代码块在类加载时执行,并且在main方法执行之前执行。
2 静态代码块一般是按照自上而下的顺序执行。
具体的业务:
项目经理说了:大家注意了,所有我们编写的程序中,只要是类
加载了,请记录一下
类加载的日志信息(在哪年哪月哪日几时几分几秒,哪个类加载
到JVM当中了)。
思考:这些记录日志的代码写到哪里呢?
写到静态代码块当中。
4.1.5 实例语句块(对象构建时机)
1 实例语句在类加载是并没有执行。
2 实例语句语法?
{
java语句;
java语句;
java语句;
}
3 实例语句块在什么时候执行?
只要是构造方法执行,必然在构造方法执行之前,自动执行“实例
语句块”中的代码。
实际上这也是SUN公司为java程序员准备一个特殊的时机,叫做
对象构建时机。有多少个
new 对象,就有多少个实例语句块执行.
4.1.6 静态代码块跟实例代码块的执行顺序
public class CodeOrder{
static{
System.out.println("A");
}
public static void main(String[] args){
System.out.println("Y");
new CodeOrder();
System.out.println("Z");
}
public CodeOrder(){
System.out.println("B");
}
{
System.out.println("C");
}
static {
System.out.println("X");
}
}
4.1.7 访问变量跟方法
实例的:一定需要使用“引用.”来访问。
静态的:
建议使用“类名.”来访问,但使用“引用.”也行(不建议使用"引用.")。
静态的如果使用“引用.”来访问会让程序员产生困惑:程序
员以为是实例的呢。
结论:
空指针异常只有在什么情况下才会发生呢?
只有在“空引用”访问“实例”相关的,都会出现空指针异常。
例子:
static String country = "中国";
Chinese c1 = null;
// 分析这里会不会出现空指针异常?
// 不会出现空指针异常。
// 因为静态变量不需要对象的存在。
// 实际上以下的代码在运行的时候,还是:System.out.println(Chinese.country);
System.out.println(c1.country);
面试题1(静态变量和实例变量的区别?)
在语法定义上的区别:静态变量前要加 static 关键字,
而实例变量前则不加。
在程序运行时的区别:实例变量属于某个对象的属性,
必须创建了实例对象,其中的实例变量才会被分配空间,
才能使用这个实例变量。静态变量不属于某个实例对象,
而是属于类,所以也称为类变量,只要程序加载了类的字
节码,不用创建任何实例对象,静态变量就会被分配
空间,静态变量就可以被使用了。总之,实例变量必须
创建对象后才可以通过这个对象来使用,静态变量
则可以直接使用类名来引用。
例如,对于下面的程序,无论创建多少个实例对象,
永远都只分配了一个 staticVar 变量,并且每创建
一个实例对象,这个 staticVar 就会加 1;但是,每创
建一个实例对象,就会分配一个 instanceVar,即可
能分配多个 instanceVar,并且每个 instanceVar 的
值都只自加了 1 次。
public class VariantTest
{
public static int staticVar = 0;
public int instanceVar = 0;
public VariantTest()
{
staticVar++; instanceVar++;
System.out.println(“staticVar=” + staticVar + ”,instanceVar=” + instanceVar);
}
}
面试题2(是否可以从一个 static 方法内部发出对非 static 方法的调用?)
不可以。因为非 static 方法是要与对象关联在一起的,必须创建一个对象后,才
可以在该对象上进行方法调用,而 static 方法调用时不需要创建对象,可以直接
调用。也就是说,当一个 static 方法被调用时,可能还没有创建任何实例对象,
如果从一个 static 方法中发出对非 static 方法的调用,那个非 static 方法是关联
到哪个对象上的呢?这个逻辑无法成立,所以,不可以一个 static 方法内部发出
对非 static 方法的调用。
4.1.8 this关键字
this:
1、this
1.1 this是一个关键字,是一个引用,保存内存地址指向
自身,是一个特殊的变量,存在于对象内部,
即在堆内存中,不是存在于栈内存中。
1.2 this可以使用在实例方法中,也可以使用在构造方法中。
1.3 this出现在实例方法中其实代表的是当前对象。
1.4 this不能使用在静态方法中。
1.5 this. 大部分情况下可以省略,但是用来区分局部变量
和实例变量的时候不能省略.也就是说除了上述情况,编译器
会自动添加this.来补充省略的this.
1.6 this() 这种语法只能出现在构造方法第一行,表示当
前构造方法调用本类其他的
构造方法,目的是代码复用。
场景:
需求:
1 定义一个日期类,可以表示年月日信息。
2 需求中要求:
如果调用无参数构造方法,默认创建的日期为:1970年1月1日。
当然,除了调用无参数构造方法之外,也可以调用有
参数的构造方法来创建日期对象。
4.1.9 类属性方法访问大总结
在同一类中,如果是静态方法的话,则可以调用静态变量或
者静态方法,但是不可以调用实例变量跟实例方法.
除非new对象再来访问实例变量跟实例方法.在同一
类中,如果是实例方法的话,则可以调用实例变量,实例
方法,静态变量,静态方法.
4.1.10 继承
继承的作用:
基本作用:子类继承父类,代码可以得到复
用。(这个不是重要的作用,是基本作用。)
主要(重要)作用:因为有了继承关系,才有了后期
的方法覆盖和多态机制。
继承的相关特性
1 B类继承A类,则称A类为超类(superclass)、父类、基类,
B类则称为子类(subclass)、派生类、扩展类。
class A{}
class B extends A{}
2 虽然 java中不支持多继承,但有的时候会产生间接继承的效果,
例如:class C extends B,class B extends A,也就
是说,C 直接继承 B,
其实 C 还间接继承 A。
子类继承父类之后,能使用子类对象直接调用父类方法吗?
可以,因为子类继承了父类之后,这个方法就属于子类了。
当然可以使用子类对象来调用。实际运行的时候,是调用子
类自己的东西,而不是父类的
东西.
3 java 中规定,子类继承父类,除构造方法不能继承之外,剩
下都可以继承。
但是私有的属性无法在子类中直接访问。(父类中private修饰
的不能在子类中
直接访问。可以通过间接的手段来访问。通过get方法来访问)
4 java 中的类没有显示的继承任何类,则默认继承 Object类,
Object类是
java 语言提供的根类(老祖宗类),也就是说,一个
对象与生俱来就有
Object类型中所有的特征。
5 继承也存在一些缺点,例如:CreditAccount 类继
承 Account 类会导致它
们之间的耦合度非常高,Account 类发生改变之后会马上
影响到 CreditAccount 类
4.1.11 方法覆盖
方法覆盖又叫做:方法重写(重新编写),英语单词
叫做:Override、Overwrite,都可以。
什么时候考虑使用方法覆盖?
父类中的方法无法满足子类的业务需求,子类有必要
对继承过来的方法进行覆盖。
什么条件满足的时候构成方法覆盖?
第一:有继承关系的两个类
第二:具有相同方法名、返回值类型、形式参数列表
注意:对于返回值类型是基本数据类型来说,必须一致。
对于返回值类型是引用数据类型来说,重写之后返回值类
型可以变的更小(但意义不大,实际开发中没人这样写。)。
第三:访问权限不能更低。
第四:抛出异常不能更多。
这里还有几个注意事项:
注意1:方法覆盖只是针对于方法,和属性无关。
注意2:私有方法无法覆盖。
注意3:构造方法不能被继承,所以构造方法也不能被覆盖。
注意4:方法覆盖只是针对于“实例方法”,“静态方法覆盖”没有意义。
关于Object类中toString()方法的覆盖?
toString()方法存在的作用就是:将java对象转换成字符串形式。
大多数的java类toString()方法都是需要覆盖的。因为
Object类中提供的toString()
方法输出的是一个java对象的内存地址。
方法重载和方法覆盖有什么区别?
方法重载发生在同一个类当中。
方法覆盖是发生在具有继承关系的父子类之间。
方法重载是一个类中,方法名相同,参数列表不同。
方法覆盖是具有继承关系的父子类,并且重写之后的方法
必须和之前的方法一致:
方法名一致、参数列表一致、返回值类型一致。
public class OverrideTest02{
public static void main(String[] args){
Bird b = new Bird();
b.move();
b.sing(1000);
Cat c = new Cat();
c.move();
}
}
class Animal{
public void move(){
System.out.println("动物在移动!");
}
public void sing(int i){
System.out.println("Animal sing....");
}
}
class Bird extends Animal{
public void move(){
System.out.println("鸟儿在飞翔!!!");
}
public void sing(){
System.out.println("Bird sing.....");
}
}
class Cat extends Animal{
public void move(){
System.out.println("猫在走猫步!!!");
}
}
4.1.12 多态
向上转型和向下转型的概念。
向上转型:子--->父 (upcasting)
又被称为自动类型转换:Animal a = new Cat();
向下转型:父--->子 (downcasting)
又被称为强制类型转换:Cat c = (Cat)a; 需要
添加强制类型转换符。
什么时候需要向下转型?
需要调用或者执行子类对象中特有的方法。
必须进行向下转型,才可以调用。
向下转型有风险吗?
容易出现ClassCastException(类型转换异常)
怎么避免这个风险?
instanceof运算符,可以在程序运行阶段动态的判断某
个引用指向的对象是否为某一种类型。
不管是向上转型还是向下转型,首先他们之间必须有继承关
系,这样编译器就不会报错。
什么是多态。
多种形态,多种状态,编译和运行有两个不同的状态。
编译期叫做静态绑定。
运行期叫做动态绑定。
Animal a = new Cat();
a.move();
// 编译的时候编译器发现a的类型是Animal,所以
编译器会去Animal类中找move()方法
// 找到了,绑定,编译通过。但是运行的时候和底层
堆内存当中的实际对象有关
// 真正执行的时候会自动调用“堆内存中真实对象”的相关方法。
多态在开发中的作用是:
降低程序的耦合度,提高程序的扩展力。
public class Master{
public void feed(Dog d){}
public void feed(Cat c){}
}
以上的代码中表示:Master和Dog以及Cat的关系很紧密(耦合度高)。导致扩展力很差。
public class Master{
public void feed(Pet pet){
pet.eat();
}
}
以上的代表中表示:Master和Dog以及Cat的关系就脱离了,Master关注的是Pet类。
这样Master和Dog以及Cat的耦合度就降低了,提高了软件的扩展性。
面向对象的三大特征:
封装、继承、多态
有了封装,有了这种整体的概念之后。
对象和对象之间产生了继承。
有了继承之后,才有了方法的覆盖和多态。
认识一个软件开发原则:
七大原则最基本的原则:OCP(对扩展开放,对修改关闭)
目的是:降低程序耦合度,提高程序扩展力。
面向抽象编程,不建议面向具体编程。
public class Test01{
public static void main(String[] args){
Animal a2 = new Cat();
a2.move();
======================================================================
Animal a5 = new Cat();
Cat x = (Cat)a5;
x.catchMouse();
Animal a6 = new Bird();
System.out.println(a6 instanceof Cat);
if(a6 instanceof Cat){
Cat y = (Cat)a6;
y.catchMouse();
}
}
}
4.1.13 调试向下转型
public class Animal {
public static void main(String[] args) {
Animal animal = new Dog();
Dog dog = (Dog)animal;
System.out.println(dog instanceof Animal);
System.out.println(dog instanceof Dog);
}
}
class Dog extends Animal {
}
4.1.14 supper
super能出现在实例方法和构造方法中。
super的语法是:“super.”、“super()”
super不能使用在静态方法中。
super. 大部分情况下是可以省略的。
super.什么时候不能省略呢?
父类和子类中有同名属性,或者说有同样的方法,
想在子类中访问父类的,super. 不能省略。
super() 只能出现在构造方法第一行,通过当前的构造
方法去调用“父类”中
的构造方法,目的是:创建子类对象的时候,先初始化父类型特征。
super的使用:
super.属性名 【访问父类的属性】
super.方法名(实参) 【访问父类的方法】
super(实参) 【调用父类的构造方法】
注意:在构造方法执行过程中一连串调用了父类的构造方法,
父类的构造方法又继续向下调用它的父类的构造方法,但是实际上
对象只创建了一个。
super 不是引用。super也不保存内存地址,super也不
指向任何对象。
super 只是代表当前对象内部的那一块父类型的特征。
System.out.println(super); //报错super不是引用
4.1.14.1 supper之间的执行顺序
public class SuperTest02{
public static void main(String[] args){
new C();
}
}
class A extends Object{
public A(){
System.out.println("1");
}
}
class B extends A{
public B(){
System.out.println("2");
}
public B(String name){
super();
System.out.println("3");
}
}
class C extends B{
public C(){
this("zhangsan");
System.out.println("4");
}
public C(String name){
this(name, 20);
System.out.println("5");
}
public C(String name, int age){
super(name);
System.out.println("6");
}
}
4.1.14.2 super跟this的比较
1、super是一个关键字,全部小写。
2、super和this对比着学习。
this:
this能出现在实例方法和构造方法中。
this的语法是:“this.”、“this()”
this不能使用在静态方法中。
this. 大部分情况下是可以省略的。
this.什
么时候不能省略呢? 在区分局部变量和实例变量的时候不能省略。
public void setName(String name){
this.name = name;
}
this() 只能出现在构造方法第一行,通过当前的构造方法去调用“本类”中
其它的构造方法,目的是:代码复用。
super:
super能出现在实例方法和构造方法中。
super的语法是:“super.”、“super()”
super不能使用在静态方法中。
super. 大部分情况下是可以省略的。
super.什么时候不能省略呢?
super() 只能出现在构造方法第一行,通过当前的构造方法去调用“父类”中
的构造方法,目的是:创建子类对象的时候,先初始化父类型特征。
3、super()
表示通过子类的构造方法调用父类的构造方法。
模拟现实世界中的这种场景:要想有儿子,需要先有父亲。
4、重要的结论:
当一个构造方法第一行:
既没有this()又没有super()的话,默认会有一个super();
表示通过当前子类的构造方法调用父类的无参数构造方法。
所以必须保证父类的无参数构造方法是存在的。
如果出现this()的话,那么当前构造方法一定没有supper().
5、注意:
this()和super() 不能共存,它们都是只能出现在构造方法第一行。
6、无论是怎样折腾,父类的构造方法是一定会执行的。(百分百的。)
4.1.15 final
final修饰的类无法继承。
final修饰的方法无法覆盖。
final修饰的变量只能赋一次值。
final修饰的引用一旦指向某个对象,则不能再重新
指向其它对象,但该引用
指向的对象内部的数据是可以修改的。
final修饰的实例变量必须手动初始化,不能采用系统默
认值。(即要赶在默认初始化之前赋值就可以,也就是说可
以在构造方法中赋值也可以,因为赶在默认初始化之前赋值了)
例子:
public class Dog {
final int a; //编译不通过。
final int b; //编译通过。
final int c = 3; //编译通过。
public Dog() {
b = 3;
}
public static void main(String[] args) {
Dog dog = new Dog();
System.out.println(dog.b);
}
}
final修饰的实例变量一般和static联合使用,称为常量。
public static final double PI = 3.1415926;
4.1.16 抽象类
抽象类:
1.抽象类属于引用数据类型。
2.抽象类怎么定义?
语法:
[修饰符列表] abstract class 类名{
类体;
}
3.抽象类是无法实例化的,无法创建对象的,所以抽象
类是用来被子类继承的。
4.final和abstract不能联合使用,这两个关键字是对立的。
5.抽象类的子类可以是抽象类。也可以是非抽象类。
6.抽象类虽然无法实例化,但是抽象类有构造方法,这个
构造方法是供子类使用的。
7.抽象类关联到一个概念:抽象方法。什么是抽象方法呢?
抽象方法表示没有实现的方法,没有方法体的方法。例如:
public abstract void doSome();
抽象方法特点是:
特点1:没有方法体,以分号结尾。
特点2:前面修饰符列表中有abstract关键字。
8.抽象类中不一定有抽象方法,抽象方法必须出现在抽象类中。
9.一个非抽象的类,继承抽象类,必须将抽象类中的抽象
方法全部进行覆盖/重写/实现。一个抽象类继承
抽象类,可以不去实现.
4.1.17 接口
接口:
1、接口也是一种“引用数据类型”。编译之后也是一个
class字节码文件。
2、接口是完全抽象的。(抽象类是半抽象。)或者也可以
说接口是特殊的抽象类。
3、接口怎么定义,语法是什么?
[修饰符列表] interface 接口名{}
4、接口支持多继承,一个接口可以继承多个接口。
5、接口中只包含两部分内容,一部分是:常量。一部分
是:抽象方法。接口中没有其它内容了。只有以上两部分。
6、接口中所有的元素都是public修饰的。(都是公开的。)
7、接口中的抽象方法定义时:public abstract修饰符可以省略。
8、接口中的方法都是抽象方法,所以接口中的方法不能有方法体。
9、接口中的常量的public static final可以省略。
4.1.18 抽象类和接口的区别。
抽象类是半抽象的。
接口是完全抽象的。
抽象类中有构造方法。
接口中没有构造方法。
接口和接口之间支持多继承.即接口可以extends多个接口
类和类之间只能单继承。这里的类包括普通类跟抽象类
一个类可以同时实现多个接口。这里的类包括普通类跟抽象类
接口中只允许出现常量和抽象方法。
面试题(判断题):java语言中凡是没有方法体的方法都是抽象方法。
不对,错误的。
Object类中就有很多方法都没有方法体,都是以“;”结尾的,但他们
都不是抽象方法,例如:
public native int hashCode();
这个方法底层调用了C++写的动态链接库程序。
前面修饰符列表中没有:abstract。有一个native。表示
调用JVM本地程序。
4.1.19 类型和类型之间的关系:
is a(继承)、has a(关联)、like a(实现)
is a:
Cat is a Animal(猫是一个动物)
凡是能够满足is a的表示“继承关系”
A extends B
has a:
I has a Pen(我有一支笔)
凡是能够满足has a关系的表示“关联关系”
关联关系通常以“属性”的形式存在。
A{
B b;
}
like a:
Cooker like a FoodMenu(厨师像一个菜单一样)
凡是能够满足like a关系的表示“实现关系”
实现关系通常是:类实现接口。
A implements B
4.1.20 关于java语言中的package和import机制:
1、为什么要使用package?
package是java中包机制。包机制的作用是为了方便程序的管理。
不同功能的类分别存放在不同的包下。(按照功能划分的,不同的
软件包具有不同的功能。)
2、package怎么用?
package是一个关键字,后面加包名。例如:
package com.yxj.javase.chapter17;
注意:package语句只允许出现在java源代码的第一行。
如何编译跟运行:比如:com.yxj.javase.chapter17.HelloWorld.java
编译:
第一种:建立 com.yxj.javase.chapter17
然后javac com.yxj.javase.chapter17.HelloWorld.java
第二种不需要建立包名目录
直接 java -d . HelloWorld.java,会自动生成 com.yxj.javase.chapter17.HelloWorld.class
运行:java com.yxj.javase.chapter17.HelloWorld
4.包名可以省略吗?
当java源文件在同一个包中时,package可以省略,否则不可以省略.
例子:
Test02在com包下。
HelloWorld在com.yxj.javase.chapter17下。
package com;
不在同一个package下,包名可以省略吗?
不能省略。
*/
4.1.21 访问控制权限
以下的4个访问控制权限:控制的范围是什么?
public 表示公开的,在任何位置都可以访问
protected表示只能在本类、同包、子类中访问。
“默认”表示只能在本类,以及同包下访问。同一包下的子类也算同包,不同包下的子类就不是同包。
private 表示私有的,只能在本类中访问,跨类不可以,同一包下子类也算跨类
访问控制修饰符 本类 同包 子类 任意位置
---------------------------------------------------------------------------
public 可以 可以 可以 可以
protected 可以 可以 可以 不行
默认 可以 可以 不行 不行
private 可以 不行 不行 不行
范围从大到小排序:public > protected > 默认 > private
访问控制权限修饰符可以修饰什么?
属性(4个都能用)
方法(4个都能用)
类(public和默认能用,其它不行。)
接口(public和默认能用,其它不行。)
4.1.22 JDK类库的根类:Object
任何一个类默认继承Object。就算没有直接继承,最终也会间接继承。
目前为止我们只需要知道这几个方法即可:
protected Object clone() // 负责对象克隆的。
int hashCode() // 获取对象哈希值的一个方法。
boolean equals(Object obj) // 判断两个对象是否相等
String toString() // 将对象转换成字符串形式
protected void finalize() // 垃圾回收器负责调用的方法
4.1.23 关于Object类中的toString()方法
System.out.println(引用); 这里会自动调
用“引用”的toString()方法。
1、源代码长什么样?
public String toString() {
return this.getClass().getName() + "@" + Integer.toHexString(hashCode());
}
源代码上toString()方法的默认实现是:
类名@对象的内存地址转换为十六进制的形式
2、SUN公司设计toString()方法的目的是什么?
toString()方法的作用是什么?
toString()方法的设计目的是:通过调用这个方法可以将一个“java对象”转换成“字符串表示形式”
3、其实SUN公司开发java语言的时候,建议所有的子
类都去重写toString()方法。
toString()方法应该是一个简洁的、详实的、易阅读的.
public class Test01{
public static void main(String[] args){
MyTime t1 = new MyTime(1970, 1, 1);
String s1 = t1.toString();
System.out.println(s1);
System.out.println(t1);
}
}
class MyTime{
int year;
int month;
int day;
public MyTime(){
}
public MyTime(int year, int month, int day){
this.year = year;
this.month = month;
this.day = day;
}
public String toString(){
return this.year + "/" + this.month + "/" + this.day;
}
}
4.1.24 String的equals方法以及toString方法。
总结:
1、String类已经重写了equals方法,比较两个字符串不
能使用==,必须使用equals。
equals是通用的。
2、String类已经重写了toString方法。
大结论:
java中什么类型的数据可以使用“==”判断
java中基本数据类型比较是否相等,使用==
java中什么类型的数据需要使用equals判断
java中所有的引用数据类型统一使用equals方法来判断是否相等。
public class Test03{
public static void main(String[] args){
String s1 = "hello";
String s2 = "abc";
String s3 = new String("Test1");
String s4 = new String("Test1");
System.out.println(s3 == s4);
System.out.println(s3.equals(s4));
String x = new String("从前慢");
System.out.println(x.toString());
System.out.println(x);
}
}
public class Test04{
public static void main(String[] args){
Student s1 = new Student(111, new String("北京大兴亦庄二小"));
Student s2 = new Student(111, new String("北京大兴亦庄二小"));
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
}
}
class Student{
int no;
String school;
public Student(){}
public Student(int no,String school){
this.no = no;
this.school = school;
}
public String toString(){
return "学号" + no + ",所在学校名称" + school;
}
public boolean equals(Object obj){
if(obj == null || !(obj instanceof Student)) return false;
if(this == obj) return true;
Student s = (Student)obj;
return this.no == s.no && this.school.equals(s.school);
}
}
4.1.25 关于Object类中的equals方法
1、equals方法的源代码
public boolean equals(Object obj) {
return (this == obj);
}
以上这个方法是Object类的默认实现。
2、判断两个java对象是否相等,不能使用“==”,因为“==”比
较的是两个
对象的内存地址。
public class Test02{
public static void main(String[] args){
int a = 100;
int b = 100;
System.out.println(a == b);
MyTime t1 = new MyTime(2018,1,1);
MyTime t2 = new MyTime(2018,1,1);
boolean flag = t1.equals(t2);
System.out.println(flag);
}
}
class MyTime {
int year;
int month;
int day;
public MyTime(){
}
public MyTime(int year, int month, int day){
this.year = year;
this.month = month;
this.day = day;
}
public boolean equals(Object obj) {
if(obj == null || !(obj instanceof MyTime)){
return false;
}
if(this == obj){
return true;
}
MyTime t = (MyTime)obj;
return this.year == t.year && this.month == t.month && this.day == t.day ;
}
}
4.1.26 finalize()方法
这个方法是protected修饰的,在Object类中这个方法的源代码是?
protected void finalize() throws Throwable { }
finalize()方法只有一个方法体,里面没有代码,而且这
个方法是protected修饰的。
GC:负责调用finalize()方法。
这个方法不需要程序员手动调用,JVM的垃圾回收器负责调用这个方法。
不像equals和toString()方法是需要你写代码调用的。
finalize()只需要重写,重写完将来自动会有程序来调用。
finalize()方法的执行时机:
当一个java对象即将被垃圾回收器回收的时候,垃圾回收器负责调用
finalize()方法。
finalize()方法实际上是SUN公司为java程序员准备的一个时机,
垃圾销毁时机。
如果希望在对象销毁时机执行一段代码的话,这段代码
要写到finalize()方法当中。
提示:
java中的垃圾回收器不是轻易启动的,
垃圾太少,或者时间没到,种种条件下,
有可能启动,也有可能不启动。
public class Test06{
public static void main(String[] args){
for(int i = 0; i < 1000; i++){
Person p = new Person();
p = null;
if(i % 2 == 0){
System.gc();
}
}
}
}
class Person{
protected void finalize() throws Throwable {
System.out.println(this + "即将被销毁!");
}
}
4.1.27 hashCode方法:
hashCode方法:
在Object中的hashCode方法是怎样的?
public native int hashCode();
这个方法不是抽象方法,带有native关键字,底层调用C++程序。
hashCode()方法返回的是哈希码:
实际上就是一个java对象的内存地址,经过哈希算法,得出的一个值。
所以hashCode()方法的执行结果可以等同看做一个java对象
的内存地址。
public class Test07{
public static void main(String[] args){
Object o = new Object();
int hashCodeValue = o.hashCode();
System.out.println(hashCodeValue);
MyClass mc = new MyClass();
int hashCodeValue2 = mc.hashCode();
System.out.println(hashCodeValue2);
MyClass mc2 = new MyClass();
System.out.println(mc2.hashCode());
}
}
class MyClass
{
}
4.1.28 内部类
1、什么是内部类?
内部类:在类的内部又定义了一个新的类。被称为内部类。
2、内部类的分类:
静态内部类:类似于静态变量
实例内部类:类似于实例变量
局部内部类:类似于局部变量
匿名内部类:属于局部内部类的一种,应用于参数传递.
3、匿名内部类是局部内部类的一种。
因为这个类没有名字而得名,叫做匿名内部类。
class Test01{
static String country;
static class Inner1{
}
int age;
class Inner2{
}
public void doSome(){
int i = 100;
class Inner3{
}
}
public void doOther(){
}
public static void main(String[] args){
MyMath mm = new MyMath();
mm.mySum(new Compute(){
public int sum(int a, int b){
return a + b;
}
}, 200, 300);
}
}
interface Compute{
int sum(int a, int b);
}
class MyMath{
public void mySum(Compute c, int x, int y){
int retValue = c.sum(x, y);
System.out.println(x + "+" + y + "=" + retValue);
}
}
4.1.29 数组
Array
1、Java语言中的数组是一种引用数据类型。不属于基本数
据类型。数组的父类是Object。
2、数组实际上是一个容器,可以同时容纳多个元
素。(数组是一个数据的集合。)
3、数组当中可以存储“基本数据类型”的数据,也可
以存储“引用数据类型”的数据。
4、数组因为是引用类型,所以数组对象是堆内存
当中。(数组是存储在堆当中的)
5、数组当中如果存储的是“java对象”的话,实际上存储
的是对象的“引用(内存地址)”,数组中不能直接存储java对象。
6、数组一旦创建,在java中规定,长度不可
变。(数组长度不可变)
7、数组的分类:一维数组、二维数组、三维数
组、多维数组...(一维数组较多,二维数组偶尔使用!)
8、所有的数组对象都有length属性(java自带的),用
来获取数组中元素的个数。
9、java中的数组要求数组中元素的类型统一。比如int类
型数组只能存储int类型,Person类型数组只能存储Person类型。
10、数组在内存方面存储的时候,数组中的元素内存
地址(存储的每一个元素都是有规则的挨着排列的)
是连续的。内存地址连续。
11、所有的数组都是拿“第一个小方框的内存地址”作为
整个数组对象的内存地址。
(数组中首元素的内存地址作为整个数组对象的内存地址。)
12、数组中每一个元素都是有下标的,下标从0开始,以1递
增。最后一个元素的下标是:length - 1
下标非常重要,因为我们对数组中元素进行“存取”
的时候,都需要通过下标来进行。
13、数组这种数据结构的优点和缺点是什么?
优点:查询/查找/检索某个下标上的元素时效率极
高。可以说是查询效率最高的一个数据结构。
为什么检索效率高?
第一:每一个元素的内存地址在空间存储上是连续的。
第二:每一个元素类型相同,所以占用空间大小一样。
第三:知道第一个元素内存地址,知道每一个元素占用
空间的大小,又知道下标,所以
通过一个数学表达式就可以计算出某个下标上元素的内
存地址。直接通过内存地址定位
元素,所以数组的检索效率是最高的。
数组中存储100个元素,或者存储100万个元素,在元素查
询/检索方面,效率是相同的,
因为数组中元素查找的时候不会一个一个找,是通
过数学表达式计算出来的。(算出一个
内存地址,直接定位的。)
缺点:
第一:由于为了保证数组中每个元素的内存地址连续,所
以在数组上随机删除或者增加元素的时候,
效率较低,因为随机增删元素会涉及到后面元素统一向前
或者向后位移的操作。
第二:数组不能存储大数据量,为什么?
因为很难在内存空间上找到一块特别大的连续的内存空间。
注意:对于数组中最后一个元素的增删,是没有效率影响的。
14、怎么声明/定义一个一维数组?
语法格式:
int[] array1;
double[] array2;
boolean[] array3;
String[] array4;
Object[] array5;
15、怎么初始化一个一维数组呢?
包括两种方式:静态初始化一维数组,动态初始化一维数组。
静态初始化语法格式:
int[] array = {100, 2100, 300, 55};
int[] a = new int[]{1,2,3};
动态初始化语法格式:
int[] array = new int[5]; // 这里的5表示数组的元素个数。
// 初始化一个5个长度的int类型数组,每个元素默认值0
String[] names = new String[6]; // 初始化6个长度的String类型
数组,每个元素默认值null。
注意:数组跟其他类型不一样,既可以在方法区内不赋
值,也可以在方法外不赋值,不赋值默认由系统赋值.
什么时候采用静态初始化方式,什么时候使用动态初始化方式呢?
当你创建数组的时候,确定数组中存储哪些具体
的元素时,采用静态初始化方式。
当你创建数组的时候,不确定将来数组中存储哪些数据
,你可以采用动态初始化的方式,预先分配内存空间。
package com.yxj.javase.array;
public class ArrayTest01 {
public static void main(String[] args) {
int[] a = {1, 100, 10, 20, 55, 689};
System.out.println("数组中元素的个数" + a.length);
System.out.println("第一个元素 = " + a[0]);
System.out.println("最后一个元素 = " + a[5]);
System.out.println("最后一个元素 = " + a[a.length - 1]);
a[0] = 111;
a[a.length - 1] = 0;
System.out.println("第一个元素 = " + a[0]);
System.out.println("最后一个元素 = " + a[5]);
for(int i = 0; i < a.length; i++){
System.out.println(a[i]);
}
for (int i = a.length - 1; i >= 0; i--) {
System.out.println("颠倒顺序输出-->" + a[i]);
}
}
}
4.1.29.1 认识main方法上面的“String[] args”
package com.yxj.javase.array;
public class ArrayTest05 {
public static void main(String[] args) {
System.out.println("JVM给传递过来的String数组参数,它这个数组的长度是?" + args.length);
for (int i = 0; i < args.length; i++) {
System.out.println(args[i]);
}
}
public static void printLength(String[] args){
System.out.println(args.length);
}
}
package com.yxj.javase.array;
public class ArrayTest06 {
public static void main(String[] args) {
if(args.length != 2){
System.out.println("使用该系统时请输入程序参数,参数中包括用户名和密码信息,例如:zhangsan 123");
return;
}
String username = args[0];
String password = args[1];
if("admin".equals(username) && "123".equals(password)){
System.out.println("登录成功,欢迎[" + username + "]回来");
System.out.println("您可以继续使用该系统....");
}else{
System.out.println("验证失败,用户名不存在或者密码错误!");
}
}
}
4.1.29.2 一维数组的深入
package com.yxj.javase.array;
public class ArrayTest07 {
public static void main(String[] args) {
int[] a = {100, 200, 300};
System.out.println(a[1]);
int[] array = {1,2,3};
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
Animal a1 = new Animal();
Animal a2 = new Animal();
Animal[] animals = {a1, a2};
for (int i = 0; i < animals.length; i++) {
animals[i].move();
}
Animal[] ans = new Animal[2];
ans[0] = new Animal();
ans[1] = new Cat();
Cat c = new Cat();
Bird b = new Bird();
Animal[] anis = {c, b};
for (int i = 0; i < anis.length; i++){
if(anis[i] instanceof Cat){
Cat cat = (Cat)anis[i];
cat.catchMouse();
}else if(anis[i] instanceof Bird){
Bird bird = (Bird)anis[i];
bird.sing();
}
}
}
}
class Animal{
public void move(){
System.out.println("Animal move...");
}
}
class Product{
}
class Cat extends Animal {
public void move(){
System.out.println("猫在走猫步!");
}
public void catchMouse(){
System.out.println("猫抓老鼠!");
}
}
class Bird extends Animal {
public void move(){
System.out.println("Bird Fly!!!");
}
public void sing(){
System.out.println("鸟儿在歌唱!!!");
}
}
4.1.29.3 数组的拷贝
public static native void arraycopy(Object src, int srcPos,Object dest, int destPos, int length);
Object src : 原数组
int srcPos : 从原数组的哪个位置开始
Object dest : 目标数组
int destPos : 目标数组的开始起始位置
int length : 要copy的数组的长度
package com.yxj.javase.array;
public class ArrayTest08 {
public static void main(String[] args) {
int[] src = {1, 11, 22, 3, 4};
int[] dest = new int[20];
System.arraycopy(src, 0, dest, 0, src.length);
for (int i = 0; i < dest.length; i++) {
System.out.println(dest[i]);
}
String[] strs = {"hello", "world!", "study", "java", "oracle", "mysql", "jdbc"};
String[] newStrs = new String[20];
System.arraycopy(strs, 0, newStrs, 0, strs.length);
for (int i = 0; i < newStrs.length; i++) {
System.out.println(newStrs[i]);
}
System.out.println("================================");
Object[] objs = {new Object(), new Object(), new Object()};
Object[] newObjs = new Object[5];
System.arraycopy(objs, 0, newObjs, 0, objs.length);
for (int i = 0; i < newObjs.length; i++) {
System.out.println(newObjs[i]);
}
}
}
4.1.29.4 二维数组
关于java中的二维数组
1、二维数组其实是一个特殊的一维数组,特殊在这
个一维数组当中的每一个元素是一个一维数组。
2、二维数组静态初始化
int[][] array = {{1,1,1},{2,3,4,5},{0,0,0,0},{2,3,4,5},{2,3,4,5},{2,3,4,5},{2,3,4,5}};
或者
int[][] array = new int[][]{{1,2,3,4},{4,5,6,76},{1,23,4}};
package com.yxj.javase.array;
public class ArrayTest12 {
public static void main(String[] args) {
int[][] array = new int[3][4];
int[][] a = {{1,2,3,4},{4,5,6,76},{1,23,4}};
printArray(a);
printArray(new int[][]{{1,2,3,4},{4,5,6,76},{1,23,4}});
}
public static void printArray(int[][] array){
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
System.out.print(array[i][j] + " ");
}
System.out.println();
}
}
}
4.1.30 常用类
4.1.30.1 String
关于Java JDK中内置的一个类:java.lang.String
1、String表示字符串类型,属于引用数据类型,不
属于基本数据类型。
2、在java中随便使用双引号括起来的都是String对象。
例如:"abc","def","hello world!",这是3个String对象。
3、java中规定,双引号括起来的字符串,是不可变的,也
就是说"abc"自出生到最终死亡,不可变,不能变成"abcd",
也不能变成"ab"
4、在JDK当中双引号括起来的字符串,例如:"abc" "def"都
是直接存储在“方法区”的“字符串常量池”当中的。
为什么SUN公司把字符串存储在一个“字符串常量池”当中
呢。因为字符串在实际的开发中使用太频繁。为了执行
效率,所以把字符串放到了方法区的字符串常量池当中。
package com.yxj.javase.string;
public class StringTest01 {
public static void main(String[] args) {
String s1 = "abcdef";
String s2 = "abcdef" + "xy";
String s3 = new String("xy");
int i = 100;
String s = "abc";
}
}
package com.yxj.javase.string;
public class StringTest02 {
public static void main(String[] args) {
String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2);
String x = new String("xyz");
String y = new String("xyz");
System.out.println(x == y);
System.out.println(x.equals(y));
String k = new String("testString");
System.out.println("testString".equals(k));
System.out.println(k.equals("testString"));
}
}
package com.yxj.javase.string;
public class StringTest03 {
public static void main(String[] args) {
String s1 = new String("hello");
String s2 = new String("hello");
}
}
4.1.30.2 String的构造方法
package com.yxj.javase.string;
public class StringTest04 {
public static void main(String[] args) {
String s1 = "hello world!";
System.out.println(s1);
System.out.println(s1.toString());
byte[] bytes = {97, 98, 99};
String s2 = new String(bytes);
System.out.println(s2.toString());
System.out.println(s2);
String s3 = new String(bytes, 1, 2);
System.out.println(s3);
char[] chars = {'我','是','中','国','人'};
String s4 = new String(chars);
System.out.println(s4);
String s5 = new String(chars, 2, 3);
System.out.println(s5);
String s6 = new String("helloworld!");
System.out.println(s6);
}
}
4.1.30.3 String的常用方法
package com.yxj.javase.string;
public class StringTest05 {
public static void main(String[] args) {
char c = "中国人".charAt(1);
System.out.println(c);
int result = "abc".compareTo("abc");
System.out.println(result);
int result2 = "abcd".compareTo("abce");
System.out.println(result2);
int result3 = "abce".compareTo("abcd");
System.out.println(result3);
System.out.println("xyz".compareTo("yxz"));
System.out.println("HelloWorld.java".contains(".java"));
System.out.println("http://www.baidu.com".contains("https://"));
System.out.println("test.txt".endsWith(".java"));
System.out.println("test.txt".endsWith(".txt"));
System.out.println("fdsajklfhdkjlsahfjkdsahjklfdss".endsWith("ss"));
System.out.println("abc".equals("abc"));
System.out.println("ABc".equalsIgnoreCase("abC"));
byte[] bytes = "abcdef".getBytes();
for(int i = 0; i < bytes.length; i++){
System.out.println(bytes[i]);
}
System.out.println("oraclejavac++.netc#phppythonjavaoraclec++".indexOf("java"));
String s = "a";
System.out.println(s.isEmpty());
System.out.println("abc".length());
System.out.println("".length());
System.out.println("oraclejavac++javac#phpjavapython".lastIndexOf("java"));
String newString = "http://www.baidu.com".replace("http://", "https://");
System.out.println(newString);
String newString2 = "name=zhangsan&password=123&age=20".replace("=", ":");
System.out.println(newString2);
String[] ymd = "1980-10-11".split("-");
for(int i = 0; i < ymd.length; i++){
System.out.println(ymd[i]);
}
String param = "name=zhangsan&password=123&age=20";
String[] params = param.split("&");
for(int i = 0; i <params.length; i++){
System.out.println(params[i]);
}
System.out.println("http://www.baidu.com".startsWith("http"));
System.out.println("http://www.baidu.com".startsWith("https"));
System.out.println("http://www.baidu.com".substring(7));
System.out.println("http://www.baidu.com".substring(7, 10));
char[] chars = "我是中国人".toCharArray();
for(int i = 0; i < chars.length; i++){
System.out.println(chars[i]);
}
System.out.println("ABCDefKXyz".toLowerCase());
System.out.println("ABCDefKXyz".toUpperCase());
System.out.println(" hello world ".trim());
String s1 = String.valueOf(new Customer());
System.out.println(s1);
System.out.println(100);
System.out.println(3.14);
System.out.println(true);
}
}
class Customer {
@Override
public String toString() {
return "我是一个VIP客户!!!!";
}
}
4.1.30.4 进行字符串的频繁拼接,会有什么问题
package com.yxj.javase.stringbuffer;
public class StringBufferTest01 {
public static void main(String[] args) {
String s = "";
for(int i = 0; i < 100; i++){
s = s + i;
System.out.println(s);
}
}
}
4.1.30.5 StringBuffer/StringBuilder解决进行字符串的频繁拼接
package com.yxj.javase.stringbuffer;
public class StringBufferTest02 {
public static void main(String[] args) {
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("a");
stringBuffer.append("b");
stringBuffer.append("d");
stringBuffer.append(3.14);
stringBuffer.append(true);
stringBuffer.append(100L);
System.out.println(stringBuffer.toString());
StringBuffer sb = new StringBuffer(100);
sb.append("hello");
sb.append("world");
sb.append("hello");
sb.append("kitty");
System.out.println(sb);
}
}
4.1.30.6 StringBuffer和StringBuilder的区别
package com.yxj.javase.stringbuffer;
public class StringBuilderTest01 {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
sb.append(100);
sb.append(true);
sb.append("hello");
sb.append("kitty");
System.out.println(sb);
}
}
String与StringBuilder/StringBuffer之间的区别?
package com.yxj.javase.stringbuffer;
public class StringBufferTest04 {
public static void main(String[] args) {
String s = "abc";
s = "xyz";
}
}
4.1.31 包装类原理实现
package com.yxj.javase.integer;
public class IntegerTest01 {
public static void main(String[] args) {
MyInt myInt = new MyInt(100);
doSome(myInt);
}
public static void doSome(Object obj){
System.out.println(obj.toString());
}
}
package com.yxj.javase.integer;
public class MyInt {
int value;
public MyInt() {
}
public MyInt(int value) {
this.value = value;
}
@Override
public String toString() {
return String.valueOf(value);
}
}
4.1.31.1 八种包装类
关于Integer类的构造方法,有两个:
Integer(int)
Integer(String)
System.out.println("int的最大值:" + Integer.MAX_VALUE);
System.out.println("int的最小值:" + Integer.MIN_VALUE);
System.out.println("byte的最大值:" + Byte.MAX_VALUE);
System.out.println("byte的最小值:" + Byte.MIN_VALUE);
其他各种Number类型依葫芦画瓢.
package com.yxj.javase.integer;
public class IntegerTest02 {
public static void main(String[] args) {
Integer i = new Integer(123);
float f = i.floatValue();
System.out.println(f);
int retValue = i.intValue();
System.out.println(retValue);
}
}
4.1.31.2 自动装箱跟自动拆箱
package com.yxj.javase.integer;
public class IntegerTest05 {
public static void main(String[] args) {
Integer x = 900;
System.out.println(x);
int y = x;
System.out.println(y);
Integer z = 1000;
System.out.println(z + 1);
Integer a = 1000;
Integer b = 1000;
System.out.println(a == b);
}
}
面试题
package com.yxj.javase.integer;
public class IntegerTest06 {
public static void main(String[] args) {
Integer a = 128;
Integer b = 128;
System.out.println(a == b);
Integer x = 127;
Integer y = 127;
System.out.println(x == y);
}
}
4.1.31.3 String int Integer之间的转换
1.int和Integer之间的转换:
1) int----->Integer
1 自动装箱
2 Integer的构造方法
3 调用Integer的静态方法:static Integer valueOf(int i):返回一个指定int值的Integer对象
代码如下:
int a = 10;
Integer i1 = a; //1
Integer i2 = new Integer(a); //2
Integer i3 = Integer.valueOf(a); //3
2) Integer------>int
1 自动拆箱
2 调用Integer的方法:int intValue():以int类型返回该Integer的值
示例代码:
Integer a = new Integer(10);
int i1 = a; //1
int i2 = a.intValue(); //2
2.String和Integer之间的转换:
1) Integer---->String
1 调用Integer的方法:String toString():返回该Integer对象的字符串形式
3 调用Integer的静态方法:static String toString(int i):返回一个指定整数的String对象
3 调用String的静态方法:static String valueOf(Object obj):返回任意类型的字符串形式
示例代码:
Integer a = new Integer(20);
String str1 = a.toString(); //1
String str2 = Integer.toString(a); //2
String str3 = String.valueOf(a); //3
2) String---->Integer
1 调用Integer的静态方法:static Integer valueOf(String s):返回指定的 String 的值的 Integer 对象。
注意:这里的参数s必须是可以解析成整数的字符串,否则会报异常:NumberFormatException
示例代码:
String str = "123";
Integer i = Integer.valueOf(str); //1
3.int和String之间的转换:
1) int------>String
1 字符串拼接,使用+
2 调用Integer的静态方法:static String toString(int i):返回一个指定整数的String对象
3 调用String的静态方法:static String valueOf(int i):返回指定int值的字符串形式
示例代码:
int a = 5;
String s1 = a +""; //1
String s3 = Integer.toString(a); //2
String s2 = String.valueOf(a); //3
2) String----->int
1 调用Integer的静态方法:static int parseInt(String s):将一个可以解析为整数的字符串解析为一个int值
2 调用Integer的静态方法:static Integer valueOf(String s):返回指定的 String 的值的 Integer 对象。【自动拆箱】
示例代码:
String str = "123";
int m1 = Integer.parseInt(str); //1
int m2 = Integer.valueOf(str); //1--->自动拆箱
int m3 = Integer.valueOf(str).intValue(); //2--->手动拆箱
4.1.31.4 日期的格式化
package com.yxj.javase.date;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateTest01 {
public static void main(String[] args) throws Exception {
Date nowTime = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
String nowTimeStr = sdf.format(nowTime);
System.out.println(nowTimeStr);
String time = "2008-08-08 08:08:08 888";
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
Date dateTime = sdf2.parse(time);
System.out.println(dateTime);
}
}
package com.yxj.javase.date;
public class DateTest02 {
public static void main(String[] args) {
long nowTimeMillis = System.currentTimeMillis();
System.out.println(nowTimeMillis);
long begin = System.currentTimeMillis();
print();
long end = System.currentTimeMillis();
System.out.println("耗费时长"+(end - begin)+"毫秒");
}
public static void print(){
for(int i = 0; i < 1000000000; i++){
System.out.println("i = " + i);
}
}
}
package com.yxj.javase.date;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateTest03 {
public static void main(String[] args) {
Date time = new Date(1);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
String strTime = sdf.format(time);
System.out.println(strTime);
Date time2 = new Date(System.currentTimeMillis() - 1000 * 60 * 60 * 24);
String strTime2 = sdf.format(time2);
System.out.println(strTime2);
}
}
4.1.31.5 数字格式化
package com.yxj.javase.number;
import java.math.BigDecimal;
public class BigDecimalTest01 {
public static void main(String[] args) {
BigDecimal v1 = new BigDecimal(100);
BigDecimal v2 = new BigDecimal(200);
BigDecimal v3 = v1.add(v2);
System.out.println(v3);
BigDecimal v4 = v2.divide(v1);
System.out.println(v4);
}
}
package com.yxj.javase.number;
import java.text.DecimalFormat;
public class DecimalFormatTest01 {
public static void main(String[] args) {
DecimalFormat df = new DecimalFormat("###,###.##");
String s = df.format(1234.561232);
System.out.println(s);
DecimalFormat df2 = new DecimalFormat("###,###.0000");
String s2 = df2.format(1234.56);
System.out.println(s2);
}
}
4.1.31.6 random
package com.yxj.javase.random;
import java.util.Random;
public class RandomTest01 {
public static void main(String[] args) {
Random random = new Random();
int num1 = random.nextInt();
System.out.println(num1);
int num2 = random.nextInt(101);
System.out.println(num2);
}
}
4.1.31.7 enum
package com.yxj.javase.enum2;
public class EnumTest02 {
public static void main(String[] args) {
Result r = divide(10, 2);
System.out.println(r == Result.SUCCESS ? "计算成功" : "计算失败");
}
public static Result divide(int a, int b){
try {
int c = a / b;
return Result.SUCCESS;
} catch (Exception e){
return Result.FAIL;
}
}
}
enum Result{
SUCCESS, FAIL
}
想要获取该该课程markdown笔记(脑图+笔记)。可以扫描以下
微信公众号二维码。或者搜索微信公众号-Java大世界。回复java1
即可获取笔记获取方式。