Java体系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
基础部分(JavaSE):
1.面向对象的编程思想
2.集合
3.I/O流 底层MVC
4.文件
5.缓存
6.反射、注解


数据库(JDBC)+WEB(JavaEE):
数据库本身为文件。注重性能提升、引擎
WEB:Socket I/O String解析


框架部分:
SSM(Spring、SpringMVC、MyBatis)
SSH(Spring、Struts、Hibernate)


其他:
Linux、Maven、Git、SVN
分布式、大数据计算

基本数据类型

1.整型

byte 一个字节为8个二进制位,在计算机中,最高为用于表示符号,并且把0放在了正数中,所以byte类型的范围转换为十进制为-128—+127
short 一个short占2个字节,-32768—+32767
int 一个int占4个字节,-2^31—+2^31-1
long 一个long占8个字节,-2^15—+2^15-1

2.浮点型

float(单精度浮点数) 4个字节
double(双精度浮点数) 8个字节

3.字符型

注意:java中默认编码集为Unicode编码集

char 2个字节
中文占2个字节,英文、符号、数字1个字节

4.布尔型

注意:C语言中bool类型可以和整型发生转变,但在Java中不可以发生转换

boolean 1个比特位(bit)

引用数据类型:

枚举(enum),类(class),注解(@interface),数组([]),接口(interface)

注意:String本质上是类,也就是引用数据类型,但是它的值很特殊,值可以简单视为常量

变量与常量

常量:基本类型的值

变量是一个空间,可以只创建空间,里面不存放内容,变量空间创建后是没有默认内容的,空的空间不能使用

在常量区中,整数默认为int(32bit),浮点数默认为double(64bit),如果定义float a=3.4;出错,因为float存不下,想要存下要人为修改,改为float a=3.4f;字母大小写都可以,long也是同样的道理,超过int范围时,后加L,大小写都可以。

byte a=1;它可以的原因,自动把没用的截取。只要十进制的没超过byte类型的范围,就可以存进去。

常量存储在常量缓冲区中

字符

字符单引号,有且只有一位。字符串存在空串,双引号。

“”:空字符串

null:什么都没有,连空串都不是

类型转换

1.同种数据类型之间可以直接进行数据转换

2.不同数据类型之间需要进行数据转换,注意:大类型之间(基本数据类型和引用数据类型)通过包装类发生转换,基本和基本类型之间可以直接转换,引用类型和引用类型之间可以直接转换

小空间的可以直接转换到大空间内。int ->double 等等

大空间放在小空间的里面,强制转换,如int->byte,double ->byte等等,(需要转换为的数据类型)

1
2
3
4
5
6
double a=129;
byte b=(byte) a;
System.out.println(b);

结果:
-127(发生溢出了)

整数与浮点数比较的为精确程度,浮点型精确度更高,可以直接转换,不是看空间,long->float可以

1.9和1强制转换都为1,小数部分直接砍掉,不是四舍五入。任何浮点型都可以存放整数

字符型与其他类型转换:(自动转化)

1
2
3
4
5
6
char a='a';
int b=a;
System.out.println(b);

结果:
97

其他类型转换为其他会出错,Error:(7, 15) java: 不兼容的类型: 从byte转换到char可能会有损失,需要强制转化,整数在做计算时,都会变为32位或者64位,即使是byte类型或者short类型。

布尔类型很特殊,不能与其他基本类型转换

运算符

运算符:用来指明操作数的运算方式

算术运算 +、-、*、/、%、++(自增)、–(自减)
赋值运算 =、-=、+=、/=、%=
关系运算 <、>、<=、>=、==、!=,instanceof对象比较
逻辑运算 &(逻辑与)、|(逻辑或)、!、^(异或)、&&(短路与)、||(短路或)
位运算(用来计算二进制) &(按位与)、|(按位或)、^(按位异或)、~(按位取反)、<<(按位左位移)、>>(按位右位移)、>>>无符号右位移

算术运算

算术运算的结果取决与参与运算的符号类型

x++等价于x=x+1

x++与x的值相同,++x的值为执行完的值

X+=10等价于X=X+10

赋值运算

1
2
3
4
5
6
7
byte v=1;
v=v+2;
System.out.println(v);

会出错,类型提升,8bit->32bit,不兼容,等号帮助值自动转换的情况是右边为常量的时候,
修正:
v=(byte) (v+2);
1
2
3
4
5
6
7
byte v=1;
v+=2;
注意:v+2,+将v自动类型提升,=再自动转换为byte

System.out.println(v);
结果:
3

深入理解内存原理:

先计算,后赋值

x++相当于x=x+1,先将x中的值取出,常量区取出1,进行计算,然后将结果再放回x空间

在进行值交换的时候,x本身会产生一个临时的副本空间(备份),++在变量的前面 ,先自增后备份,++在变量的后面,先备份后自增,会将临时副本空间的值赋给别人。之后临时空间就会被销毁了。

1
2
3
4
5
6
7
8
double x=5;
double y=x++;
System.out.println(x);
System.out.println(y);

结果:
6.0
5.0
1
2
3
4
5
6
7
8
9
double x=5;
double y=++x;
System.out.println(x);
System.out.println(y);


结果:
6.0
6.0

赋值又赋回来了,2被1覆盖掉,所以不变,一开始的1和最后的1不一样

1
2
3
4
5
6
int m=1;
m=m++;
System.out.println(m);

结果:
1

笔试题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int m=1;
for (int z=0;z<100;z++){
m=m++;
}
System.out.println(m);

结果仍为1

int m=1;
int n=2;
int sum=m++ + ++n -n-- - --m + n-- - --m;
System.out.println(sum);

结果为2

逻辑运算前后必须是两个boolean型的结果

异或:两者相同为0,不同为1

短路与或 比 逻辑与或 性能稍好

1
2
3
4
5
&&因为只要当前项为假,它就不往后判断了,直接认为表达式为假
||因为只要当前项为真,它也不往后判断了,直接认为表达式为真
-----------------------------------------------------------------------------------
&同为1时为1,否则为0
|同为0时为0,否则为1

位运算

位运算:将十进制数转换为二进制数,然后按照对应位置&、|、^,最后将得到的结果再转换为十进制

常量默认为32位

八进制最前面用0表示,用于与10进制区分,16进制开头用0X表示

计算机中所有的数都是用补码表示的,其中反码是表示形式,取反是一个计算过程(每一个位置都取反)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
**笔试题**:
最有效率的方式计算2*8的结果:
2<<3


两个变量int a=1;int b=2;如何交换两个变量的值
1)开辟中间变量进行交换(较容易理解,但浪费了一个新的内存空间)
2)a=a+b;
b=a-b;
a=a-b;
(省略了新的空间,不好在于相对较难理解,但可能在运算过程中产生越界问题)
(3)a=a^b;
b=a^b;
a=a^b;
(一个数字异或同一个数字两次,值不会发生改变,异或值的范围,不会太大,也就不容易产生越界问题)

Java语法结构

顺序结构 代码顺序执行
分支结构 单分支(if ……else……)、多分支(switch)
循环结构 while、do…while、for

输入

Scanner引用数据类型,

1
2
3
Scanner sc=new Scanner(System.in);
String name = sc.nextLine();
System.out.println(name);

随机数:Math.random()范围0-1之间的小数[0.0,1.0)

==与equals()的区别

基本类型比较用等号,引用类型在用==作比较的时候,比较的不是值,而是地址,因为引用类型存的就是地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Test {
public static void main(String[] args) {
String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2);//true


String str3 = new String("abc");
String str4 = new String ("abc");
System.out.println(str3==str4);//false
System.out.println(str3.equals(str4));//true
}
}


先看第3行代码,先在栈中创建一个对 String类的对象引用变量str1,然后通过引用去字符串常量池 里找有没有"abc",如果没有,则将"abc"存放进字符串常量池。这里常量池中并没有“abc”。即在编译期已经创建好(直接用双引号定义的)“abc”,存储在了常量池中。

4行代码又创建了对String类的对象引用str2,然后通过引用去字符串常量池 里找有没有"abc",如果没有,则将"abc"存放进字符串常量池 ,并令str2指向”abc”,如果已经有”abc” 则直接令str2指向“abc”。这里我们在第三行代码中已经将“abc”这个字符串存储进了常量池。所以str2和str1指向的是同一个“abc”,返回true

8行和第9行代码分别创建了2个对象,str3和str4指向的是不同的对象,即上面所说的内存空间中存储位置不同。故str3 == str4 返回的肯定是false

11行代码 str3.equals(str4) 返回true

因为String类重写了equals方法,比较的是内存空间存放的数据是否相同。这里存放的都是字符串“abc” 故返回true

注意:值可以为byte、short、int、char、String(1.7版本以上),eunm(1.5版本以上),char可以转换为整数计算,实际上都为数值

1
2
3
4
5
6
7
8
9
10
11
12
switch(值){
case1:
代码1
break;(否则会继续执行下去)
case2
代码2
break;
default:(类似于if语句中最后的else
代码;
}

注意:各个值的结果要与switch后的值类型一致

循环结构

循环:重复不停的做同样事情,而不是同件事情

栈内存:从声明开始,用完就会回收

for允许将3个必要条件都写在括号内,不是必须

1
2
3
for(初始值;终点判定条件;变化量){
执行代码;
}

Math.pow(a,b);帮我们计算a的b次方,再进行输入时,a和b都为double类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//画星星
Scanner input = new Scanner(System.in);
System.out.println("请输入行数");
int line = input.nextInt();
for (int l = 0; l < line; l++) {
if (l == 0) {
for (int j = 0; j < 2 * line - 1; j++) {
System.out.print("*");
}
} else {
for (int j = 1; j <= line - l; j++) {
System.out.print('*');
}
for (int j = 1; j <= (l + 1) * 2 - 3; j++) {
System.out.print('#');
}
for (int j = 1; j <= line - l; j++) {
System.out.print('*');
}
}
System.out.print('\n');
}

//结果:
请输入行数
8
***************
*******#*******
******###******
*****#####*****
****#######****
***#########***
**###########**
*#############*



//while语句

System.out.println("请输入行数:");
Scanner input = new Scanner(System.in);
int num = input.nextInt();
int i = 1;
while (i <= num) {
//画空格
int k = 1;
while (k <= num - i) {
System.out.print(' ');
k++;
}
//画*号
int j = 1;
while (j <= 2 * i - 1) {
System.out.print('*');
j++;
}
i++;
System.out.print('\n');
}

//结果:
请输入行数:
6
*
***
*****
*******
*********
***********

注意:写程序不能满足只写出来,要注重程序的可复用性

转义字符:\,可以转换特殊的字符,将身后的一个字符意思发生转换。

\n 换行
\r 回车
\t 制表符(输出内容按表格处理)

回车与换行的区别:

1
2
3
4
5
\r 回车是将光标移到一行的前面, \n 是移到下一行 。

在windows下实现换行需要\r\n,而在UNIX,Linux下只要\n即可。

在windows环境下,换行就是另起一行,回车就是回到一行的开头,所以在平时我们编写文件的回车符确切来说叫做回车换行符。
1
2
3
4
5
6
7
8
9
10
11
12
13
//判断素数

for (int i = 2; i <= 100; i++) {
System.out.print(i);
//判断该数是否为素数
for (int j = 2; j <= i - 1; j++) {
if (i % j == 0) {
System.out.print('不');
break;
}
}
System.out.println("是素数");
}

关于for循环中的break语句,满足就近原则,当在嵌套循环中使用时,满足就近原则,终止最近的循环

continue:中断本次循环,继续执行下一次循环

1
2
3
4
5
6
7
8
9
while语句:
-------------------------------------
初始值;
while(终点判定条件){
执行代码;
变化量
}

while语句实际上为for语句的变体
1
2
3
4
5
6
7
do……while()语句:
----------------------------------------
初始值;
do{
执行代码;
变化量;
}while(终点判断条件);

do……while与while的区别:

do……while 先执行代码,后判断,条件不满足至少执行一次
while 先判断,后执行,条件不满足就不执行

Java数组

数据和变量一样,都可以作为容器,数组可以存放一数据类型相同的数据的组合。

数组本身是一个引用数据类型,数组内存储的类型可以是基本类型,也可以是引用数据类型(如字符串类型)

1
2
3
4
5
6
7
数组的定义(声明):
-------------------------------------
数据类型[] 数组名字;

这两种定义形式也可以,但不规范
数据类型 数组名字[];
数据类型 []数组名字;

数据的赋值(初始化):

1.静态初始化

1
2
3
4
int[] array = new int[]{10, 20, 30, 40, 50};

如果数组前面存在定义,如上所示,则可以直接赋值,即:
int[] array = {10, 20, 30, 40, 50};

JDK1.5版本—>J2SE—>JavaSE5.0

新特性:增强for循环

1
2
3
for(自己定义的变量(为了接收数组内每一个元素):遍历的数组名字){
。。。。。
}
1
2
3
4
5
6
7
8
9
10
11
12
13
//加强循环例子

int[] array = new int[]{10, 20, 30, 40, 50};
for (int value:array){
System.out.println(value);
}

结果:
10
20
30
40
50

增强for缺点:只能取值,不能存值,没有index索引,找不到元素到底是哪个

2.动态初始化

1
2
有长度,没有元素
int[] array =new int[5];

注意:

1
2
3
int[] m=new int[0];

这种情况编译执行都能通过,如果是负数则会出错,运行时异常

动态初始化有长度,一开始未初始化则使用默认值,整数默认值为0,浮点数为0.0,字符型默认值为0对应的字符,布尔类型默认值为false,引用数据类型默认为null

1
2
3
4
5
String[] m = new String[2];
System.out.println(m[0]);

//结果:
null

数组长度:array.length

重点:基本数据类型和引用数据类型在内存结构上的区别

内存大概:

栈内存:

堆内存:

存储区:常量区、方法区(类)、静态区(static)

基本类型变量空间存储的为值,传递的就是值

引用类型变量空间存储的是地址(引用),传递的就是引用

所有的变量空间都存储在栈内存

变量空间可以存储基本数据类型,也可以存储引用数据类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
例子:

public static void main(String[] args) {
int a = 10;
int b = a;
b = 100;
System.out.println(a);

int[] x = {10, 20, 30};
//赋值实际为x的地址
int[] y = x;
//改变y[0]实际上改变的为x[0]
y[0] = 100;
System.out.println(x[0]);
}

结果:
10
100

数组作为栈内存中的小容器

注意:见到new关键字,相当于在堆内存中申请开辟一块新的空间。数组在堆内存的空间状态是一串连续的地址,堆内存的数组空间长度一旦确定,不能再次发生改变,另外数组在初始化时必须指定长度

数组X中存的实际上为HashCode,简单理解为首元素的地址

元素个数比较少,静态

元素个数很多,动态

例题:

1.交换两个数组的值:当两数组个数相等时:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int[] a = {1, 2, 3, 4};
int[] b = {5, 6, 7, 8, 9};
for (int i = 0; i < a.length; i++) {
a[i] = a[i] ^ b[i];
b[i] = a[i] ^ b[i];
a[i] = a[i] ^ b[i];
}
System.out.println("a:");
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]);
}
System.out.print('\n');
System.out.println("b:");
for (int i = 0; i < a.length; i++) {
System.out.print(b[i]);
}

当两数组个数不等时:

交换数组地址:一次搞定,不受数组长度限制

1
2
3
4
int[] c;
c = a;
a = b;
b = c;

2.保留非0数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int[] a = {1, 2, 3, 0, 0, 4, 5, 0, 6, 0, 7};
int sum = 0;
for (int i = 0; i < a.length; i++) {
if (a[i] != 0) {
sum++;
}
}
int[] b = new int[sum];
int k = 0;
for (int i = 0; i < a.length; i++) {
if (a[i] != 0) {
b[k++] = a[i];
}
}
// 旧数组已经没用了,手动释放降低内存消耗
a = null;
for (int value : b) {
System.out.print(value + " ");
}

结果:
1 2 3 4 5 6 7

3.创建一个数组,存储2-100之间的素数(质数)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int[] a = new int[98];
int sum = 0;
for (int i = 2; i <= 100; i++) {
int j = 2;
for (; j <= i - 1; j++) {
if (i % j == 0) {
//不是素数
break;
}
}
if (j == i) {
//说明是素数
a[sum++] = i;
}
}
int[] newarray = new int[sum];
for (int i = 0; i < sum; i++) {
newarray[i] = a[i];
}
a = null;
for (int i = 0; i < sum; i++) {
System.out.print(newarray[i] + " ");
}

这个思路是牺牲部分空间换取时间,另一种思路是提前确定素数个数,根据个数节省空间,但时间消耗更为严重

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//冒泡排序,完全根据“冒泡”表面意思来的

for (int j = 1; j < a.length; j++)
for (int i = a.length - 1; i >= j; i--) {
if (a[i] < a[i - 1]) {
int temp = a[i];
a[i] = a[i - 1];
a[i - 1] = temp;
}
}

for (int i = 0; i < a.length; i++) {
System.out.print(a[i]);
}

二维数组:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

//声明
数据类型[][] 数组名

//初始化

静态初始化:
int[][] array={{},{},,,,, };
动态初始化:
int[][] array=new int[x][x];

//数组的遍历||轮询

需要双层循环访问:
int[][] a={{1,2},{3,4,5},{6,8,9}};
for (int i=0;i<a.length;i++){
int b= a[i].length;
for (int j=0;j<b;j++){
System.out.print(a[i][j]+" ");
}
System.out.print('\n');
}

增强循环:
for (int[] arr : a) {
for (int value : arr) {
System.out.print(value + " ");
}
System.out.print('\n');
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
二维数组在内存中的存储:

注意:在内存中二维数组实际为树状结构,如不指定第二位长度会出现空指针异常(NullPointerException)

例:(难)
int[][] array = new int[3][2];
array[0][0] = 10;
array[0][1] = 20;
array[1] = array[0];
array[0] = new int[4];
array[1][0] = 100;
System.out.println(array[1][0]);


结果:10

mian方法:

1
2
3
4
5
6
7
8
9
10
11
public static void main(String[] args){

}

public:访问权限修饰符 共有的
static: 特征修饰符 静态的 有且只有一份
void:方法执行完没有返回值 关键字
main 方法名字 主要的

1.主方法不是我们调用的,JVM虚拟机启动的时候虚拟机调用的
2.主方法中有args参数,是一个String类型,我们是可以传递参数进去给JVM

测试:

1
2
3
4
5
6
System.out.println(args.length);
for (String value:args){
System.out.print(value+" ");
}

结果为0,空串

Java—-面向对象的编程思想

类:抽象笼统的概念,用来描述一类事物,这类事物具有相同的特征和行为。

对象:具体的实体

(1)创建一个类
(2)在类的里面,利用属性或方法去描述这个类
(3)创建一个当前类的对象,让对象调用属性/方法做事

属性描述:权限修饰符 [特征修饰符] 数据类型 属性名字 [=值];

属性默认是只有同包或者本类访问,主方法属于JVM虚拟机

对象的创建在哪里都可以,使用new关键字创建,通过 对象.去调用属性进行存值和取值或者方法

在内存中经JVM的ClassLoader类加载器加载到方法区,形成类的映射,这个映射并不是完整的类文件

new出来的对象存放在堆内存中,所以有默认值存在,依照各属性数据类型赋默认值

例子:注意输出结果

1
2
3
4
5
6
7
8
9
10
11
12
Person p = new Person();
p.age = 18;
p.name = "Kennan";
Person p2 = p;
p2.name = "Faker";
p2.age = 20;
System.out.println("姓名:" + p.name + "年龄:" + p.age);
System.out.println("姓名:" + p2.name + "年龄:" + p2.age)

结果:
姓名:Faker年龄:20
姓名:Faker年龄:20

类中的方法描述:

权限修饰符 [特征修饰符] 返回值类型 方法名字(参数列表) [抛出异常] [{

方法体 }]

面向对象之方法参数返回值问题:(核心)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class Person {

public void changeNum(int x) {
System.out.println("方法执行开始:" + x);
x = 10;
System.out.println("方法执行结束:" + x);
}

public static void main(String[] args) {

//隐藏的一步:加载类模板的过程,加载到方法区

//在堆内存中开辟空间,与方法区中类模板结构一致,p对象进到栈内存中,指针指向堆内存的开辟空间
Person p = new Person();

//栈内存
int a = 1;

//调用方法执行
//方法是堆内存中的方法,方法存储在堆内存对象空间内
//方法执行where? 栈内存中开辟一块临时空间来执行方法,x中存储的为a的值,后来将10存入x,第二次输出变成10
p.changeNum(a);
//整个方法执行完毕后,临时空间会被清除,但a的变量空间还在,并且还是一开始的值,所以a不会改变
System.out.println(a);
}
}

执行结果:

方法执行开始:1
方法执行结束:10
1

如果上述过程想让a发生改变,可在临时空间消失之前将10拿出来,即返回出来,添加return语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public int changeNum(int x) {
System.out.println("方法执行开始:" + x);
x = 10;
System.out.println("方法执行结束:" + x);
return x;
}

public static void main(String[] args) {
Person p = new Person();
int a = 1;
a = p.changeNum(a);

System.out.println(a);
}

结果:
方法执行开始:1
方法执行结束:10
10

如果内容是基本类型,传递的是值,形参改变,实参不变

如果内容是引用类型,传递的是引用,形参改变,实参跟着改变

注意:

String类型是一种特殊类型的引用类型,对String进行的任何修改,String都会新产生一个对象,存放修改后的String。

堆内存可以简单理解为仓库,其中只能存储,不能做处理数据的操作,所有的执行过程都不能在堆内存中执行

命名规则和规约

规则

字母、数字、符号、中文

字母 区分大小写

数字 不能开头

符号 _$

中文不推荐使用

规约

类名字:首字母大写 两个单词以上 每一个首字母大写:Test、TestOne……

属性/方法/变量:驼峰式命名规约 首字母小写 两个单词以上 第二个以后的每一个首字母大写 :test、testOne 、testOneTwo……

构造方法:与类名一致 ;类中唯一的大写字母开头的方法

静态常量: 全部首字母大写 通过_做具体说明:BOOKESTORE_ADMIN

包名:全部字母小写,java关键字都是小写,注意与关键字不要冲突

所有的名字最好见名知义,增强可读性

操作属性规约:

age——>存 setAge()、获取getAge()

私有属性对应方法:getName()、setName()……

方法重载overload

最常见的就是System.out.println();

概念:一个类中的一组方法,相同的方法名字,不同的参数列表,这样的一组方法构成了方法重载

作用:为了让使用者便于记忆和调用

参数的个数、参数的类型或者参数顺序有一个不同就是重载

方法参数传递,类型之间的转化问题:类型转换必须保证大数据类型必须一致,String为引用类型,char为基本类型,无法转换 。

char可以和int转换

1
2
3
4
5
6
char x='a';
int y=x;
System.out.print(y);

结果:
97

如果方法名字有一致,可以通过参数的数据类型定位方法

如果没有与传递参数类型一致的方法,可以找一个参数类型可以进行自动转换的

JDK1.5版本之后,出现了新写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
动态参数列表
int... x

个数0到n之间都可以

public void test(int... x){
System.out.print(x.length);
}


public static void main(String[] args) {
Person p = new Person();
p.test(1,2,3,4,5,6);
}

结果:
6

x本质上就是一个数组,有length属性,有索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void test(int... x){
System.out.println(x.length);
System.out.print("是动态传参的形式");
}

public void test(){
System.out.print("不是动态传参的形式");
}


public static void main(String[] args) {
Person p = new Person();
p.test();
}

结果:
不是动态传参的形式

动态参数列表的方法不能与相同意义数据类型的方法构成重载,因为本质上是一样的

动态参数列表在方法参数中只能存在一份,且必须放置在方法参数的末尾

构造方法

只有这一个方法名字大写字母,没有特征修饰符,返回值类型

作用:只有一个构建当前类的对象

注意:构造方法存在返回值,可以接收

写法:

1
2
3
4
权限修饰符 与类名一致的方法名(参数列表)[抛出异常]{
一件事情,创建一个对象
返回对象;
}

用法:通过new关键字调用

特点:

1.每个类都有构造方法,若自己在类中没有定义,系统会默认提供一个无参数的构造方法。若在类中自己定义了构造方法,则默认无参数的构造方法即被覆盖。

2.构造方法存在重载

为什么使用?

你可以在创建对象的同时做一些其他事情

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class Person {
String name;
int age;
//重写构造方法

public Person(String n, int g) {
name = n;
age = g;
System.out.println("姓名:" + name + " 年龄:" + age);

}
}




public class Main {
public static void main(String[] args) {
Person p = new Person("刘方涵", 20);

}

}

结果:
姓名:刘方涵 年龄:20

建议:

在自己定义带参数的构造方法的同时,将系统不带参数的构造方法一并写出来构成构造函数的重载

传参与属性重名时,用this代替当前调用方法时的那个对象

1
2
3
4
5
6
7
8
9
10
11
12
public class Person {
String name;
int age;
//重写构造方法

public Person(String name, int age) {
this.name=name;
this.age=age;
System.out.println("姓名:" + this.name + " 年龄:" + this.age);

}
}

程序块(代码块)

理解为一个方法,非常特殊,无参数无返回值无名字,也就无修饰符

作用:跟普通方法一样,做事情的

写法:

1
2
3
{

}

他是类的成员,写在类中

用法:块也需要调用才能执行,我们自己在每次调用构造方法之前,系统帮我们自动调用一次

特点:没有重载的概念,当存在多个代码块时,按照编写顺序执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public Person(String name, int age) {
this.name=name;
this.age=age;
System.out.println("姓名:" + this.name + " 年龄:" + this.age);

}

{
System.out.println("Hello");
}
}


public class Main {
public static void main(String[] args) {
Person p = new Person("刘方涵", 20);

Person q = new Person("the shy", 21);

}
}


结果:
Hello
姓名:刘方涵 年龄:20
Hello
姓名:the shy 年龄:21

可以在块中写一些程序,我想要在创建对象之前执行

this关键字的使用

1.关键字。代替的是某一个对象(当前调用属性或方法的那个对象)

2.this代替的是一个对象,则可以调用属性和方法

3.调用属性和方法这一行代码可以放置在类中的任何成员位置

this可以在一个构造方法内调用另一个构造方法,但在一般方法中不能调用构造方法,因为有顺序,先执行构造方法才能调用一般方法,但在构造方法中调用其他构造方法是写法为this();省略了构造方法的名字,构造方法与类名一致,所以省略。

在构造方法中调用另一个构造方法中this(xx)必须放在第一行,在构造方法中不能来回调用

this方法之间来回调用,编译会通过,即写法可以,但在执行时会发生错误:StackOverflowError:栈溢出错误,新的临时空间一直产生,旧的临时空间还未释放

循环标记

标签在循环中可以改变循环执行的流程。而这种改变不是我们以前单独使用break或者是continue能够达到的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
outer1:  
for(int i =0;i<4;i++){
System.out.println("begin to itrate. "+i);
for(int j =0;j<2;j++){
if(i==2){
continue outer1;
// break;
}
System.out.println("now the value of j is:"+j);
}
System.out.println("******************");
}



执行的结果是:
begin to itrate. 0
now the value of j is:0
now the value of j is:1
******************
begin to itrate. 1
now the value of j is:0
now the value of j is:1
******************
begin to itrate. 2
begin to itrate. 3
now the value of j is:0
now the value of j is:1
******************

类:包括属性、方法、构造方法、程序块(代码块)

修饰符:private:只有在当前类的内部才能访问(数组类编写)

权限修饰符

大小比较:public>protected>private

关系

泛化(继承、实现)

A is a B

存在父类和子类,类与对象就是抽象和具体的关系,使用继承可以减少代码冗余

语法:

子类继承父类,通过关键字extends实现

继承特点:

1.子类在继承父类后,可以调用父类中的(public protected限定的)属性和方法,当作自己的来使用

2.除此之外,子类可以添加自己独有的方法属性使用

3.子类从父类中继承过来的方法不能满足子类的需要,可以在子类中重写(覆盖)父类的方法

4.每一个类都有继承类,如果不写extends关键字,默认继承Object,写了的话就继承后面的那个类。

5.Java中的继承是单个存在的,每个类只能有一个继承类,在extends后面只能写一个类,目的是为了让类更加的安全。但可以通过传递的方式实现多继承的效果

6.Object类是任何一个引用类型的父类(都直接或者间接的继承Object),Object没有父类

1
2
3
4
5
6
Object中的toString()方法

public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
//16进制
}

Object类public权限方法

toString() 在打印输出时将一个对象变成一个字符串
equals() 用来比较两个对象的内容,底层为==
hashCode() 将对象在内存中的地址经过计算转化为int整数
getClass() 获取对象对应类的类映射(反射)
wait() 线程进入挂起等待状态(存在重载)
notify() 线程进入唤醒状态
notifyAll() 唤醒所有线程
finalize() protected 类似于析构函数,GC时调用
clone() protected 将对象拷贝一份的

7.继承在内存中的存储形式:

类似于洋葱,一层一层包裹起来,子类构造方法执行时父类的也会创建

8.this和super的使用:

this关键字,代替当前调用方法属性时的那个对象,不一定是当前类的

super代替的是当前执行方法时的对象的父类对象

都能调用一般属性和一般方法,可以调用构造方法,放在第一行

注意调用一般方法的时候可以来回互相调用(写法 编译好用),执行可能出现问题栈溢出异常

构造方法之间不能来回户想调用(编译就不好用),子类构造方法执行时会先调用构造方法,在子类构造中隐藏super(),如果来回调用,super方法就会被覆盖,父类无法调用构造方法,出错。也就说super和this可以同时出现,但在构造方法中同时出现是不行的

包含(组合、聚合、关联)

A has a B

组合:(如:人和大脑、人与心脏) 整体关系,不可分割。要出现都出现,要消亡都消亡
聚合:(如:汽车和车轮,电脑和主板) 整体和部分的关系,其实能分割。关系不如组合紧密
关联:(如:人有汽车、人有电脑) 整体和部分,可以分割,后来形成在一起的

Java描述:通过一个类的对象作为另一个类的属性

依赖(最常见的关系)

A use a B

不是整体和部分的关系,某一件事情产生了关系

临时组合在一起,这件事情做完关系即解散

Java程序体现的形式为:一个类的方法中使用到了另一个类的对象

(1)可以在方法中传递参数

(2)可以在方法中自己创建

修饰符

分类:

权限修饰符(从大到小):

​ public:公共的

​ protected:受保护的

​ 默认不写:默认的

​ private:私有的

特征修饰符:

​ final:最终的,不可改变的

​ static:静态的

​ abstract:抽象的

​ native:本地的,本国的(hasCode方法就是这样的)

​ *transient:瞬时的,短暂的——–》序列化

synchronized:同步的,*修饰方法**的

volatile:*修饰属性**的,不稳定的


权限修饰符:
修饰什么?

1.权限修饰符能够修饰类、类中的属性和方法(程序块除外)和构造方法

2.权限修饰符在修饰类时只有两种(public、默认不写)

一个文件中可以编写多个类,但只允许有一个public类

3.权限修饰符都可以用来修饰类中的成员

特点:

四者都能在本类中访问

同包:package相同的才是同包,package路径不同的不算同包

public 本类、同包、子类,当前项目中任意类的位置只要有对象都能访问
protected 本类、同包、子类范围内部通过子类对象访问,但父类访问不到,保护方法只能让子类调用
默认不写 本类、同包
private 本类

特征修饰符:

修饰什么?

修饰变量、属性、方法、类

public final class Test{}

特点:

1.final:最终的,不可修改的。可以修饰变量、属性、方法、类

修饰变量:如果在定义变量时没有赋初值,给变量一次存值的机会,变量在栈内存空间内没有默认值。

特点:

一旦变量被存储了一个值,若用final修饰后不能改变,相当于常量。如果修饰的变量为基本数据类型,则变量内的值不让更改,修饰的为引用数据类型,则变量内的地址引用不让更改

修饰属性:全局变量,存储在堆内存的对象空间内的空间,属性如果没有赋值,有默认值存在的,属性用final修饰后,必须给属性赋初值,否则编译报错,特点与修饰变量一致

修饰方法:方法是最终的方法,不可更改。即不可以被子类重写(覆盖)

修饰类本身:表示类是最终的,不可修改。此类不能被其他的子类继承。

​ 通常都是一些定义好的工具类

2.static:静态的

可以修饰属性、方法、块(块唯一拥有的东西)、修饰*内部类**

修饰后的所有特点都是一样的

(1)静态元素在类加载时就初始化了,很早,此时没有创建对象

(2)静态元素存储在静态元素区中,每个类都有自己的,每一个不冲突

(3)静态元素只加载一次,全部的类对象及类本身共享

(4)由于静态元素区加载时,有可能没创建对象,可以通过类名字直接访问

(5)垃圾回收只能回收栈内存和堆内存的,静态元素区GC(Garbage Collection)无法管理,可以粗暴的认为常驻内存

(6)非静态成员(堆内存对象里)中可以访问静态成员(静态区)

(7)静态成员可以访问静态成员(都存在静态区中)

(8)静态成员中不可以访问非静态成员。一个出发访问一堆相同名字的成员,静态成员属于类,非静态成员属于对象自己的

(9)this指代当前调用方法时的对象。静态成员属于类,所以静态成员 中不能出现this或super关键字

3.abstract:抽象的(不具体,只是个概念,没有具体执行)

只能修饰类、方法。是用来描述事物的,但不清晰

抽象方法:只有方法结构,没有方法体,使用abstract抽象

普通类不能含有抽象方法,在类中添加abstract使类变成抽象类

注意:抽象方法一定在抽象类或接口中,但抽象类中不是必须含有抽象方法的

特点:

研究思想:

(1)类里面有什么

可以含有属性,与正常的类没有区别

可以含有一般的方法,比一般类多的是允许含有抽象的方法

块是一种特殊的方法,可以含有

可以含有构造方法,包括重载

(2)类的使用

抽象类含有构造方法,但不能通过调用构造方法直接创建对象

抽象类只能通过子类单继承来做事

why不能掉用?

自己是”残次品“,可能创建出来的方法不能用

但必须有,这样子类才能用

(3)类与类的关系

抽象类可以直接单继承抽象类、具体类(用法通常不会出现)

具体类不可以直接单继承抽象类,需要把抽象方法具体化才行或具体类转化为抽象类

抽象类中没有具体成员全部都是抽象方法,即抽象到了极致,即发生了质的变化,叫做接口

接口不用class修饰,使用interface修饰,

1
2
3
public interface 类名{
……
}

接口中的属性只能含有公有静态常量,即public static final

不能含有一般方法,只能含有公有的抽象方法,1.8之后可以使用default来修饰一般方法

不能含有大括号,所以静态和一般的代码块就没有了,块本身就是具体的

不能含有构造方法

接口只为了定义规则,不描述具体过程

接口只能通过子类多实现(implements)来做事

1
2
3
public class A implements B,C,D){
……
}

与个别类的关系:

抽象类直接多实现接口

具体类不能直接多实现接口类,必须将接口中的抽象方法具体化或自己变成抽象类

接口不能继承别的类,他是最抽象的

*接口与接口之间是多继承的

4.native:本地的,源代码中看到就已经再也看不到后续代码了

后续调用其他的编程语言c/c++执行内存的操作。

注意:用native修饰的方法不是抽象方法,虽然也没有方法体,他是执行的过程是其他语言写的,看不见

Object类中的hashCode()

类的加载机制顺序

1.加载父类模板

2.父类产生自己的静态空间,按照顺序依次为属性、方法、静态块

3.执行父类静态块

4.加载子类模板

5.子类产生自己的静态空间,按照顺序依次为属性、方法、静态块

6.执行子类静态块

7.开辟对象空间

8.加载父类的非静态成员,按照顺序依次为属性、方法、块、构造方法

9.执行块、执行父类的构造方法

10.加载子类的非静态成员,按照顺序依次为属性、方法、块、构造方法

11.将对象空间的地址引用交给变量来存储

多态

同一个对象,体现出来的多种不同的形态(身份)将一种行为表现出不同的结果

想要实现多态的效果,首先存在继承关系

1体现:父类类型引用指向子类的对象

例:Person p =new Teacher(); //这是个真老师,但体现出来的身份是人的身份

2结果:该引用体现的身份,该引用只能调到父类中定义的属性和方法

3.如果子类中将父类的方法重写了,那么调用方法后执行的结果是子类重写之后的那个结果(跟属性无关)

4.如果想要调用子类的独有的属性方法,需要将类型还原回真实类型,强制类型转换

Teacher t = (Teacher)p;

5.造型时(强制向下转型时)可能会出现运行异常(ClassCastException:类造型异常)

对象 instanceof 类:对象属于类或该类的子类,避免出现异常

看真实的对象

内部类

指的是在Java中可以将一个类定义在另一个类的内部,一般只有自己用的类写在自己类里面

内部类定义

(1)类的内部(与类成员层次一致)

(2)方法/块内部(与类成员相差一个层次,与方法的局部变量一个层次)

分类:

成员内部类、局部内部类、匿名内部类(成员匿名内部类、局部匿名内部类)、静态内部类(成员静态内部类static)


成员内部类

1.成员内部类可以访问外部类的所有成员。

2.内部类属于外部类的,相当于外部类成员。

1
2
3
Demo demo = new Demo();//创建外部类
Demo.InnerDemo a = demo.new InnerDemo();//这样才能创建内部类对象
a.test();//使用内部类的方法

3.当内部类成员与外部类的成员发生重名时,使用外部类.this.外部类成员来进行访问 Demo.this.name

4.小细节:在内部类存在后,源代码编译产生字节码,如Demo$InnerDemo.class

局部内部类

定义在方法里面或块里面,相当于局部变量,方法执行完,类即被回收。只能用abstract或final修饰,其他不行构造方法不行

使用的变量只能是final的

匿名内部类:

不能用任何的修饰符来说修饰,匿名内部类没有构造函数

1
2
3
4
5
6
7
8
9
public interface Test{
public void test();
}

主函数中:

Test t = new Test(){
public void test(){……}
}

静态内部类:

成员静态内部类

不需要外部对象

静态成员不能访问非静态成员

public static class A{}

枚举类

引用类型:数组、类、抽象类、接口、枚举、注解

一个类中的对象,认为个数是有限且固定的(季节、天数……),可以挨个将每个对象一一列举出来

自己手动设计:

private构造方法

public static final 属性= new ……;

1
2
3
4
5
6
7
8
9
public enum Day{
//相当于描述了7个当前类的对象
monday,tuesday,wednesday……
}

public static void main(String[] args){
Day a = Day.monday;

}

1.枚举类型都会默认继承Object类、Enum类

name:名字 ordinal:顺序(在枚举类的索引)

2.valueOf():通过给定的name获取对应的枚举对象

values():在Enum源码中没有,虚拟机加载时手动放的。获取全部的枚举对象,装在数组中返回。 Day[]

compareTo():可以比较两个枚举对象,返回int,整数表示,越靠近前面的数字越小,按照索引。

3.switch内部判断枚举的应用

4.可以在enum中描述自己的一些属性或方法,必须在enum类的第一行描述枚举对象的样子,可以定义自己的属性。需要提供构造方法,必须是私有的

1
2
3
4
5
6
7
8
9
10
11
12
public enum Day{

monday("星期一",1),tuesday,wednesday;

private String name;
private int index;
private Day(){}
private Day(String name,int index){
this.name = name;
this.index = index;
}
}

Runtime类

提供了几个管理内存的方法

1
2
3
4
Runtime r = Runtime.getRuntime();
long max = r.maxMemory();//整个堆内存空间大小
long total = r.totalMemory();//可以用的堆内存空间
long free = r.freeMemory();//空闲的堆内存空间

小细节

1.Java在编写时,类名要大写。

2.在进行编译和运行时,默认不加修饰符,编译形成的文件为类名.class(Test.java–>Demo.class)。在加上public 后,强制要求类名必须要与文件名一致(Test.java–>Test.class),否则出错,这样编译出来的class文件就会与类名一致。

3.在进行输出时,System.out.println();自带换行, System.out.print();不带换行

4.方法重载:overload。一个类中的一组方法

方法重写(覆盖):override。子类重写父类的方法,发生在继承中

方法重写 方法重载
权限修饰符 子类可以大于等于父类 没有要求
特征修饰符 final static abstract 父类方法为final,子类不能重写 ;父类方法为static,子类不存在;父类方法为abstract,子类必须重写(子类是具体的必须重写,否则子类是抽象类,可以不重写) 没有要求
返回值 子类可以小于等于父类 没有要求
名字 子类与父类一致 一致
参数 子类与父类一致 必须不一致(个数、类型、顺序)
异常 父类方法抛出运行时异常,子类可以不予理会;父类方法抛出编译时异常时,子类抛出异常的个数和类型都要小于等于父类 没有要求
方法体 子类的方法应该与父类不一致 应该不一致

5.类的个数变多,需要管理–》使用包,当package和import同时出现时,先写package后写import,包只能有一个,import可以有多个

6.设计类的关系遵循的原则:高内聚(自己的事情只与自己有关)低耦合(别人的事情与自己无关)

耦合度最高的为继承,然后包含,最后依赖

7.Java面向对象的四个特征(继承、封装、多态、(抽象))

封装:将一些数据或执行过程进行一个包装,目的是为了保护这些数据或执行过程的安全,方法本身就算是封装

8.堆内存的空间存在默认值,栈内存的没有默认值

异常

InputMisMatchException:输入类型不匹配(要求输入整数输入了字符),字符自动转换为整数,整数不能自动转换为字符

ArrayIndexOutOfBoundsException:数据索引越界异常

NegativeArraySizeException:运行时异常。创建数组时数组长度给了负数,数组的长度不合法

NullPointerException:空指针异常(空元素在使用时出现的)

NumberFormatException:数字格式化异常(abc无法转化为数字……)

ArithmeticException:(运行时异常,变异不会出错)数学异常 例(100/0)

ClassCastException:类造型异常(多态)

IllegalArgumentException:非法参数异常(int result = r.nextInt(0);)

相关文章
评论
分享
  • JavaEE开发准备

    个人电脑硬件配置: Windows 10 64位家庭中文版 8G运行内存 Intel(R) Core(TM) i5-7300HQ CPU @ 2.50GHz 1.Java JDK安装及配置(1)下载和安装首先进入oracle网站中Ja...

    JavaEE开发准备
  • JSP综合作业

    预备:数据库本次作业选择的数据库为MYSQL,采用的数据库管理工具为Navicat Premium12。MYSQL下载地址为https://dev.mysql.com/downloads/mysql/ 使用Navicat连接数据库。 ...

    JSP综合作业
  • JSP实现简单的购物车

    主要知识点:jsp指令标记、动作标记、内置对象request、response、session等的使用。 直接上代码: login.jsp: 1234567891011121314151617181920212223242526272...

    JSP实现简单的购物车
  • JSP初识

    JSP(Java Server Page),由Sun公司倡导,许多公司参与,于1999年(与我年龄一样!!!)推出的一种Web服务设计标准。 注释HTML注释: 1<!--需要注释的HTML内容--> JSP注释: 1&...

    JSP初识
  • Java工具类

    API(Application Programming Interface)1.包装类Java是面向对象的语言,但其中存在基本类型,违背了面向对象的思想。 包装类是基本类型与引用类型之间交换的桥梁 类型 包装类 byte ...

    Java工具类
  • Java设计模式

    设计模式:设计模式常用的有23种。设计模式是一种设计经验的总结,为了解决某些场景下的某一类的问题,是一种通用的解决方案 创建型(5):解决对象创建的过程 结构型(7):把类或对象通过某种形式结合在一起 行为型(11):解决类或对象之间...

    Java设计模式
  • Scanner类的学习

    Scanner类导包:java.util 创建对象:Scanner input =new Scanner(System.in); 使用: int value = input.nextInt(); ​ String va...

    Scanner类的学习
  • 引用类型对象方法返回值问题

    想要通过对象方法交换两个数组中的值 目前采用了两种方法: (1)一次交换二者数组中的值 (2)交互两数组的数组名 (1) 1234567891011121314151617181920212223242526272829303132...

    引用类型对象方法返回值问题
  • Windows下neo4j的安装

    neo4j是一个高性能的NOSQL图形数据库,他将结构化数据存储在网络上而不是表中。他是一个嵌入式的、基于磁盘的、具备完全的事物特性的Java持久化引擎,neo4j也可看做是一个高性能的图引擎,该引擎具有成熟数据库的所有特性。——百度...

    Windows下neo4j的安装
  • java实现类FTP程序

    继承程序设计实验,实验说明如图所示: 集成程序设计实验 TCP实现首先说明下基于TCP实现的功能: (1)能够实现多用户的同时连接 (2)用户执行成功的命令会在其他用户终端上显式说明 (3)当前用户数以及在线情况会在服务端实时显...

    java实现类FTP程序
Please check the comment setting in config.yml of hexo-theme-Annie!