byte:Java中最小的数据类型,在内存中占8位(bit),即1个字节,取值范围-128~127,默认值0
short:短整型,在内存中占16位,即2个字节,取值范围-32768~32717,默认值0
int:整型,用于存储整数,在内在中占32位,即4个字节,取值范围-2147483648~2147483647,默认值0
long:长整型,在内存中占64位,即8个字节-2^63~2^63-1,默认值0L
float:浮点型,在内存中占32位,即4个字节,用于存储带小数点的数字(与double的区别在于float类型有效小数点只有6~7位),默认值0
double:双精度浮点型,用于存储带有小数点的数字,在内存中占64位,即8个字节,默认值0
char:字符型,用于存储单个字符,占16位,即2个字节,取值范围0~65535,默认值为空
boolean:布尔类型,占1个字节,用于判断真或假(仅有两个值,即true、false),默认值false
数据类型在计算机语言里面,是对内存位置的一个抽象表达方式,可以理解为针对内存的一种抽象的表达方式。接触每种语言的时候,都会存在数据类型的认识,有复杂的、简单的,各种数据类型都需要在学习初期去了解,Java是强类型语言,所以Java对于数据类型的规范会相对严格。数据类型是语言的抽象原子概念,可以说是语言中最基本的单元定义,在Java里面,本质上讲将数据类型分为两种:基本类型和引用数据类型。
基本类型:简单数据类型是不能简化的、内置的数据类型、由编程语言本身定义,它表示了真实的数字、字符和整数。
引用数据类型:Java语言本身不支持C++中的结构(struct)或联合(union)数据类型,它的复合数据类型一般都是通过类或接口进行构造,类提供了捆绑数据和方法的方式,同时可以针对程序外部进行信息隐藏。
在Java中,每个存放数据的变量都是有类型的,如:
char ch; float x; int a,b,c;
ch是字符型的,就会分配到2个字节内存。不同类型的变量在内存中分配的字节数不同,同时存储方式也是不同的。
所以给变量赋值前需要先确定变量的类型,确定了变量的类型,即确定了数据需分配内存空间的大小,数据在内存的存储方式。
1)基本数据类型的存储原理:所有的简单数据类型不存在“引用”的概念,基本数据类型都是直接存储在内存中的内存栈上的,数据本身的值就是存储在栈空间里面,而Java语言里面八种数据类型是这种存储模型;
2)引用类型的存储原理:引用类型继承于Object类(也是引用类型)都是按照Java里面存储对象的内存模型来进行数据存储的,使用Java内存堆和内存栈来进行这种类型的数据存储,简单地讲,“引用”是存储在有序的内存栈上的,而对象本身的值存储在内存堆上的;
区别:基本数据类型和引用类型的区别主要在于基本数据类型是分配在栈上的,而引用类型是分配在堆上的(需要java中的栈、堆概念),
基本类型和引用类型的内存模型本质上是不一样的。
例1:我们分析一下”==“和equals()的区别。
首先,我定以两个String对象
Stringa="abc";
Stringb="abc";
然后
if(a==b){
System.out.println("a==b");
}else{
System.out.println("a!=b");}
程序输出a!=b
原因:a和b的地址是不相同的,a==b比较的是两个变量的地址
例2:定义两个基本类型
int a=4;
int b=4;
if(a==b){System.out.println("a==b");}
else
{System.out.println("a!=b");}
输出:a==b
原因:==比较的是两个变量的内容
猜想:不论是基本数据类型还是引用类型,他们都会先在栈中分配一块内存,对于基本类型来说,这块区域包含的是基本类型的内容;而对于对象类型来说,这块区域包含的是指向真正内容的指针,真正的内容被手动的分配在堆上。
从计算机组成原理的角度可以解释:
byte在计算机中是占8个字节的,而且byte 是有符号整形,用二进制表示时候最高位为符号位 0代表正数 1代表负数。
最大值:127 即2的7次方减去1;最小值:即2的7次前面加个负符号:-128 。(包含开始,不包含结尾);
正数在计算机中是以原码形式存在的;
负数在计算机中是以其补码形式存在的,就是负数的绝对值的原码转为二进制再按位取反后加1。
下边这个10和-10为例来介绍的 :10原码:00001010 它在计算机中的存储就是 0000 1010,-10 按照前面说的算除其绝对值为10,转为二进制 0000 1010 按位取反 1111 0101 再加1后:1111 0110,此为-10补码,好的,计算机中的1111 0110就是代表-10了。
我们来看 -128 绝对值128的二进制表示:1000 0000 按位取反 0111 1111 加1后:1000 0000,也就是说 -128在计算机中的表示就是 1000 0000 了,再来看一下-129 在计算机中的表示,绝对值129的范围已经超出了了byte的位数。所以要注意这类问题;
1、概述:
Java中的数据类型分为引用数据类型和基本数据类型。
引用数据类型分3种:类,接口,数组;
基本数据类型又分布尔类型和数值类型;
布尔类型:boolean(逻辑型) trure or false默认是false;
数值类型分定点类型和浮点类型;
定点类型分整数类型和字符型;
2、JAVA变量的默认初始化
类型 |
默认初始化值 |
boolean |
false |
int |
0 |
short |
0 |
float |
0.0 |
double |
0.0 |
char |
\ |
long |
0 |
byte |
0 |
object |
null |
3、类型详细讲解:
1)整数类型:byte、short、int、long都是表示整数的,只不过他们的取值范围不一样。
byte(字节类型)一个byte 8位,取值范围为-128~127,占用1个字节(-2的7次方到2的7次方-1)默认是0
short(短整型)一个short 16位,取值范围为-32768~32767,占用2个字节(-2的15次方到2的15次方-1)默认是0
int(整型) 一个int 32位,取值范围为(-2147483648~2147483647),占用4个字节(-2的31次方到2的31次方-1)默认是0
long(长整型) 一个long 64位,取值范围为(-9223372036854774808~9223372036854774807),占用8个字节(-2的63次方到2的63次方-1)默认是0L或0l推荐用大写;
可以看到byte和short的取值范围比较小,而long的取值范围太大,占用的空间多,基本上int可以满足我们的日常的计算了,而且int也是使用的最多的整型类型了。在通常情况下,如果JAVA中出现了一个整数数字比如35,那么这个数字就是int型的,如果我们希望它是byte型的,可以在数据后加上大写的 B:35B,表示它是byte型的,同样的35S表示short型,35L表示long型的,表示int我们可以什么都不用加,但是如果要表示long型的,就一定要在数据后面加“L”。
1.1)定点常量
定点常量是整型常数,它可用十进制、八进制、十六种进制三种方式来表示。
十进制定点常量:如123、-456、0。
八进制定点常量:以0前导,形式为0dd...d。如0123表示十进制数83,-011表示十进制数-9。
十六进制定点常量:以0x或0X开头,如0x123表示十进制数291,-0X12表示十进制数-18。
1.2)定点变量
定点变量即整型变量,可细分成字节型变量、整型变量、短整型变量和长整型变量四种。
对各种定点变量的开销内存字节数和数值范围作简要说明。
需要注意的是,如果要将一定点常量赋值给一个定点变量,需要查验常量是否在该变量的表达范围内,如超出范围程序会编译出错。
2)char型(字符型)
Java中一个字符(char)表示Unicode字符集中的一个元素。
Unicode字符由16位组成,因此,有(65535)个不同的字符可用,
Unicode字符集包含所有不同语言的字符,以及数学、科学、文字中的常用符号,所以给了我们很大的灵活性。
字符由单引号括起来的单个字符表达,通常用16进制表示,
范围从’’到’?’(u告诉编译器你在用两个字节[16位]字符信息表示一个Unicode字符)。
用于存放字符的数据类型,占用2个字节,采用unicode编码,它的前128字节编码与ASCII兼容,
字符的存储范围在\~\?,在定义字符型的数据时候要注意加' ',比如 '1'表示字符'1'而不是数值1。
2.1)字符常量
字符常量指用单引号括起来的单个字符,如‘a’,‘A’,请特别注意,字符的定界符是单引号,而非双引号。
除了以上所述形式的字符常量值之外,Java还允许使用一种特殊形式的字符常量值,
这通常用于表示难以用一般字符来表示的字符,这种特殊形式的字符是以一个“\”开头的字符序列,称为转义字符。
Java中的常用转义字符见表
2.2)字符变量
以char定义的变量,如char c='a';
要特别加以说明的是,Java的文本编码采用Unicode集,Java字符16位无符号型数据,一个字符变量在内存中占2个字节。
注:charc = ' 1 ',我们试着输出c看看,System.out.println(c);结果就是1,而如果我们这样输出呢System.out.println(c+0);结果却变成了49,这是因为0是int型,进行了向上类型转换,结果是个int型。
如果我们这样定义c看看,char c = ' \1 ';输出的结果仍然是1,这是因为字符'1'对应着unicode编码就是\1。
3)浮点类型:分float和double是表示浮点型的数据类型,他们之间的区别在于他们的精确度不同。
3.1)浮点常量
即带小数点的实型数值,可以由直接带小数点的数值和科学计数法两种形式来表示:
带小数点的数值形式:由数字和小数点组成,如0.123、.123、123.、123.0。
科学计数法表示形式:由一般实数和e±n(E±n)组成,如12.3e3、5E-3,它们分别表示12.3乘以10的3次方,5乘以10的-3次方。需要注意的是,e或E之前必须有数字,且e或E后面的指数必须为整数。
3.2)浮点变量
浮点变量有单精度变量和双精度变量之分,不同的精度开销的内存字节数和表达的数值范围均有区别。两种浮点变量占内存字节数和数值范围
浮点常量也有单精度和双精度之分,前面列出的常量均是双精度常量,如果要特别说明为单精度常量,可以数据末尾加上f或F作为后缀,如12.34f。如果要特别指明一个浮点常量是双精度常量,数据末尾不需要添加后缀,或者在数据末尾加上d或D作为后缀,如12.34d。
float (单精度浮点型)一个float 32位,占用4个字节,例3.2F,默认是0.0f,3.402823e+38 ~1.401298e-45(e+38表示是乘以10的38次方,同样,e-45表示乘以10的负45次方)。
double (双精度浮点型)一个dobule 64位 占用8个字节,例3.2,默认是0.0,1.797693e+308~4.9000000e-324 占用8个字节
注:double型比float型存储范围更大,精度更高,所以通常的浮点型的数据在不声明的情况下都是double型的。
如果要表示一个数据是float型的,可以在数据后面加上“F”。 浮点型的数据是不能完全精确的,所以有的时候在计算的时候可能会在小数点最后几位出现浮动,这是正常的。
相关介绍:
在Java基本类型在使用字面量赋值的时候,有几个简单的特性如下:
1】当整数类型的数据使用字面量赋值的时候,默认值为int类型,就是直接使用0或者其他数字的时候,值的类型为int类型,所以当使用 long a = 0这种赋值方式的时候,JVM内部存在数据转换。
2】浮点类型的数据使用字面量赋值的时候,默认值为double类型,就是当字面两出现的时候,JVM会使用double类型的数据类型。
3】从JDK 5.0开始,Java里面出现了自动拆箱解箱的操作,基于这点需要做一定的说明:
对应原始的数据类型,每种数据类型都存在一个引用类型的封装类,分别为Boolean、Short、Float、Double、Byte、Int、 Long、Character,这些类型都是内置的封装类,这些封装类(Wrapper)提供了很直观的方法,针对封装类需要说明的是,每种封装类都有一个xxxValue()的方法,通过这种方法可以把它引用的对象里面的值转化成为基本变量的值,不仅仅如此,每个封装类都还存在一个valueOf(String)的方法直接把字符串对象转换为相应的简单类型。
在JDK5.0之前,没有存在自动拆解箱的操作,即Auto Box操作,所以在这之前是不能使用以下方式的赋值代码的:Integer a = 0;//这种赋值方式不能够在JDK 1.4以及以下的JDK编译器中通过,但是JDK 5.0出现了自动拆解箱的操作,所以在JDK 5.0以上的编译器中,以上的代码是可以通过的
引用数据类型:
数组
String:字符串型,用于存储一串字符
Java变量声明及使用:
数据类型变量名=值、表达式;
例:Stringname = "柯南";
int a= 50;
注:“=”并不是数学中的“等号”,而是一个赋值运算符
Java变量命名规则:
1:必须以字母、下划线“_”、或“$”符号开头
2:可以包括数字、区分大小写
3:不能使用Java语言的关键字,例如int、class、public等
Java中的六种运算符:
· 算术运算符
· 赋值运算符
· 关系运算符
· 逻辑运算符
· 位运算符
· 三元运算符
算术运算符:
+:加法运算,求操作数的和
-:减法运算,求操作数的差
*:乘法运算,求操作数的乘积
/:除法运算,求操作数的商
%:求余运算,求操作数相除的余数
++:自增,操作数自加1
--:自减,操作数自减1
赋值运算符:
=:将右边的值赋给左边,例:int a = 1;
+=:左右两边的和相加赋给左边,例:int a = 1; a+=2;结果a的值为3
-=:左边减去右边的差赋给左边,例:int a =5;a-=2;结果a的值为3
*=:两边数值相乘的值赋给左边,例:int a = 2;a*=2;结果a的值为4
/=:左边除以右边的值赋给左边,例:int a = 6;a/=2;结果a的值为3
%=:左边除以右边的余数赋给左边,例:int a =7;a%=2;结果a的值为1
关系运算符
>:大于,例:int a = 1;int b =2;System.out.print(a > b);其结果为false
<:小于,例:int a = 1;int b =2;System.out.print(a < b);其结果为true
>=:大于等于,例:int a = 1;int b =2;System.out.print(a >= b);其结果为false
<=:小于等于,例:int a = 1;int b =2;System.out.print(a <= b);其结果为true
==:等于,例:int a = 1;int b =2;System.out.print(a == b);其结果为false
!=:不等于,例:int a = 1;int b =2;System.out.print(a != b);其结果为true
其结果都是boolean类型,即要么是true要么是false
逻辑运算符
&&:与、并且(短路), 两个条件同时为真时,结果为真
||:或、或者(短路), 两个条件有一个为真时,结果即为真
!:非,(!+条件) 条件为真时,结果为假
Java中的数据类型转换
1:自动数据类型转换(放大转换)
满足自动数据类型转换条件:
1)两种类型要兼容:如数值类型(整型和浮点型)
2)目标类型大于源类型:例如int型数据可以自动转换为double类型
2:强制数据类型转换(缩小转换)
在变量前加上括号,在括号中指定要强制转换的类型
例:doublea = 40.9;
int b= (int)a;
注:强制转换会损失数值精度,例如double类型变量a,经强制转换为int类型后值变为40
1、概念:数组是相同数组类型的集合。
2、声明数组:
intc;
int[] a;
double[] b;
//:不恰当的声明,容易产生歧义。
int d[];
3、数组没有初始化,无法进行操作
int d[];
system.out.println(d); //编译错误
4、数组的初始化:静态初始化、动态初始化
动态初始化:a = newint[]{11,34,1000,39}; //new操作符会在堆中开辟空间,存放数组元素。
Int[] a2 = new int [3];
for(int i =0; i < a2.length;i++){
System.out.println(a2[i]);
}
System.out.println(a2);
静态初始化:
int[] a3 ={10,20,30}; //声明数组,初始化数组
要求记忆单词element 元素。
5、数组的增删改查
1)增加
int[] a4 = new int[6];
a4[0] = 12;
a4[1] = 43;
a4[2] = 43;
a4[3] = 43;
a4[4] = 43;
a4[5] = 43; //赋值方法比较慢(不建议使用)
for(int I = 0 ; I < a4.length;i++){
a4[i] = I;
}
2)访问数组:通过数组的下标,就是数组的各个元素的索引(index),从0开始,到数组长度-1结束。
访问数组通常会抛出一种异常:元素索引超出异常。(数组越界)
for(int i=0;i
System.out.println(a4[i]);
}
3)复制数组
int[] x={12,13,45,67};
int[] y={123,345,567,789};
//需求:将x数组中的元素进行修改,改成y一样
for(int i = 0; i
x[i]=y[i];
}
//遍历修改的x数组
for(int element:x){
System.out.println(element);
}
4)删除:数组没有删除这个说法,为什么?数组长度是固定的,如果不要某个数组不可以删除,只能将它重置成零。
5)特点:数组是相同数据类型的集合,数组访问起来效率非常高,因为每个元素都是索引值。
6、二维数组 (多维数组)
1)二维数组其实是数组的嵌套
2)二维数组初始化:
int[] [] a = newint[3][2]; //动态初始化
int[][]b={{11,44},{33,46},{66,52}}; //静态初始化
int[][]c={{1,23,45,67},{6,9},{10},{12,100}}; //静态初始化
3)二维数组的访问:
for(int i = 0; i
for(int j = 0;j < c[i].length;j++){
System.out.print(c[i][j]+"");
}
System.out.println();
}
7、冒泡排序
//如果有n个数,从里面找出最大的,需要比较n-1次
//如果有n个数,找老大需要找出n-1次
int[]a={12,3,67,21,100,5,25,78};
int swap = 0;
for(int i = 0;i
//找7次:100 78 67 25 21 12 5 3 不用找,所以7次
/*
* 第一次找100:需要比较7次
* 第一次找78:需要比较6次
* 第一次找67:需要比较5次
* 第一次找25:需要比较4次
* 第一次找21:需要比较3次
* 第一次找12:需要比较2次
* 第一次找5:需要比较1次
*/
for(int y =0; y < a.length-i-1;y++){
//这里面就是每次比较的逻辑
//12,312,67 67,21
int tmp= 0;
if(a[y]>a[y+1]){
tmp= a[y];
a[y]= a[y+1];
a[y+1]= tmp; //这样大的数到了后面
swap++;//统计交换的次数
}
}
}
for(intelement:a){
System.out.println(element);
}
8、补充知识点:
//引用类型:对象类型,接口类型,数组类型,集合类型
//引用类型变量如果赋值,默认值null
//1.对象类型
Person p; //对象类型
Fly f; //接口类型
char[] c; //数组类型
List s; //集合类型
1、方法:
a) 封装特定的逻辑功能,独立的事。
b) 多次调用,避免重复,复用,维护,团队协作开发。
2、定义:
a) 修饰词 返回值类型 方法名(参数列表){
方法体
}
3、调用:
a) 无返回值:方法名(有参传参);
b) 有返回值: 数据类型 变量 = 方法名(有参传参);
方法名(有参传参); //真确,但不建议这样写
4、return
a) return值; //结束方法,返回结果给调用方法。
b) return; //结束方法
5、猜字游戏
ObjectOriented Programming 面向对象的程序设计;
Ø 区别:()
a) 语言基础:
Ø 固定(去银行取钱,画圆形)
Ø 猜字符小游戏
b) 面向对象:
Ø 抽象(向着社会主义发展,画圆形)
Ø 飞机大战
Ø 高质量的代码:
a) 复用性
b) 维护性
c) 扩展性
d) 可移植性
e) 健壮性
Ø 什么是面向对象?
a) 面向对象就是一个类中有一个或者多个方法,被另外一个类调用,或被另一个类中的方法弟调用,说白了就类与类之间的方法调用,或本类方法与方法之间的调用,称之为面向对象。
b) 面向对象的结构化程序设计:
a) 结构化程序的弊端:
Ø 缺乏对数据的封装(包一起)
Ø 数据和方法(对数据的操作)的分离。
Ø 为什么有类的存在?类的存在就是为了解决结化构编程的弊端。
Ø 结构化程序的弊端,缺乏对数据的封装:
Ø 解决方法:封装成一种类型:
1. 基本数据类型---不够 (各个类型之间,没有办法成为彼此的容器。或者说没有任何一个数据类型。能够称为所有类型的容器)
2. 数组---不行 (数据只能装相同的数据类型)
3. 自己造一个类型(类)
4. 结构化程序的弊端,数据和方法(对数据的操作)的分离。
5. 解决方法:将方法封装到类的内部:
Ø 什么事抽象数据类型:指就是类。
所谓的抽象数据类型可以理解为:将不同类型的数据的集合成一个整体用来描述一种新的事物(类)。
Ø 什么是对象?什么是类?
1. 现实世界是由很多对象组成的。基于对象抽出了类。
2. 对象:真实存在的单个的个体。类:类型/类别,一类个体。
3. 示例:
对象 类
张老师 老师
王老师
南老师
每一个老师都一个真实存在的个体,所以都是对象。
所有的老师,都是教师,所有他们归成一类。
张三 学生
李四
王五
所以说对象是类的实例化(就是对象是类,实际存在的实际例子)。
4. 自己的理解:
a) 对象是类的事例化(对象是类实际存在的例子),类是指从基于对象抽出的类,比如说老师是一类,那么类中的各个成员变量和方法,就是从各个对象抽调的特性(成员变量)。实例化这个类,就可以调用这写属性(成员变量)和 方法。这就是面向对象。
5. 类中可以包含什么?
a) 所有对象所共有的特征/属性----变量。
b) 所有对象所共有的行为(动)--方法。
c) 例如:
老师:特征/属性 姓名、年龄、地址
老师:行为/方法 授课、唱歌、
d) 一个的特征或行为特多了,需要用到写,不要不写。
6. 一个类可以创建多个对象
a) 同一个类的多个对象,结构相同,数据不同。(具体的值不一样)
7. 类是对象的模板,对象是类的具体的事例。
8.
Ø 如果创建类?如果创建对象?
类的定义包括“成员变量”的定义和“方法”的定义,其中“成员变量”用于描述该类型对象共同的数据类型结构。
Class 类名{ 成员变量类型 变量名称;返回值 方法名{方法体}}
通过new关键字创建对象。 User e = new User();
创建对象的过程也叫对象,对象实例化的过程。
New JFrame()可以创建一个窗体对象。
Java.swing.JFrame是JDK提供的一个类,用封装显示在桌面上的一个窗体。
例:类型 引用类型变量 = new 对象();
Student zs = new Student();
9. 为什么要创建对象?
a) 为了能够对实例化的对象进行访问控制,需要使用一个特殊的变量—引用。
b) 引用类型变量可以存放该类对象的地址信息,通常称为“指向该类的对象”;当一个引用类型变量指向该类的对象时,就可以通过这个变量对象进行访问。
c) 除了8种基本类型之外,类、接口、数组、枚举、标注,等变量声明称为引用类型变量,简称“引用”。
10. 引用类型的变量的赋值
1)只有new关键字后面的才会在内存中开辟空间。
2)用于接收的变量和基础数据类型的变存储在栈中,指向堆。
3)引用类型变量存储的是对象的地址信息。相同类型的引用类型变量之间也可以相互赋值。
4)引用类型变量之间的赋值不会创建新的对象,但有可能会使两个以上的引用指向同一个对象。
5)Emp e1 = new Emp();
Emp e2 = new e1; //将e1的值(对象的地址信息)赋值给e2,e2和e1指向相同的对象。
e1.name = “毛不易”; //通过引用e1和e2操作的是相同的对象
e1.name = ”毛泽东”;
System.out.println(e1.name); //毛泽东,对象只有一个,赋值永远是最后一个生效。
11. 引用类型之间画等号:指向了同一个对象(总结)
1)对其中一个引用的修改会影响另一个引用
a) 房子:对象、钥匙(多把),多把钥匙开同一个门。
2)基本类型之间画等号:赋值
a) 例如:身份证和复印件,再怎么复印省份证原件也不可能修改。
3)
12. Null和nullPointerException
1)对于引用类型变量,可以对其赋值为null。Null含义为“空”,表示还没有指向任何对象。例如:
Emp emp = null;
//引用emp中的值为null,没有指向任何对象。
emp = new Emp();
//引用emp指向了一个Emp对象。
2)当一个引用的值为null的时候,如果通过引用访问对象成员变量或者调用方法是不合逻辑的。此时,会产生NullPointerException。
JFrame frame = null;
Frame.setSize(200,300);
1、对象创建后,其成员变量可以按照默认的方式初始化。
2、初始化对象成员变量时,其默认值的规定如下表:
成员变量类型 |
默认初始值 |
数值类型(byte、short、int、long、float、double) |
0 |
boolean |
false |
char |
/u0000 |
引用类型(对象类型):类、接口、数组、枚举、标注 |
null |
1、步骤:
1)找对象:一堆小格子
2)抽类:格子类
3)设计类中的成员变量和方法
4)创建对象并测试
1、概念:方法的签名包如下两个方面:方法名和参数列表。
2、规则:一个类中,不可以有两个方法的签名完全相同,即一个类中不可以有两个方法的方法和参数列表都完全一样。
3、如果一个类的两个方法只是方法名相同而参数列表不同,是可以的。这就方法的重载。
1、同一个类中,允许多个方法的名称相同,但参数列表不同,称之为方法的重载(overload)。
Publicclass PayMoney{
Public boolean pay (double money){}
Public boolean pay(String cardld,StringcardPwd}{}
Public boolean pay(StringcompayName,double money){}
}
2、编译时根据签名绑定调用方法
a) 编译器在编译时会根据签名来绑定调用不同的方法,我们可以把重载的方法看成是完全不同的方法,只不过恰好方法名相同而已。
Public class PayMoney{
Public boolean pay (double money){}
Public boolean pay(String cardld,StringcardPwd}{}
Public boolean pay(StringcompayName,double money){}
}
Pay(8888.88); //调用方法1
Pay(“23123”,44444); //调用方法2
Pay(“tarent”,33433.5); //调用方法3
3、注意:调用方法的时候,参数类型必须匹配。
4、总结:方法重载(Overload):
1)同一类中,方法名称相同,参数列表不同。
2)编译器在编译时自动根据方法的签名来绑定调用不同的方法。
5、补充知识点:
1)同一个文件中可以包含多个类。
2)public修饰的类只能有一个。
3)public修饰的类必须与文件名相同。
Public class Demo{ public static voidmain(String[] args) }
class Test{
void sayHi(){}
void sayHi(String name){}
void sayHi(int age){}
void sayHi(String name,int age){}
void sayHi(int age,String name){}
int sayHi(){return 1;} //编译错误,与返回值无关
void sayHi(String address){} //编译错误,与参数名称无关。只看类型
}
1、意义:常常用于给成员变量赋初始值。
2、规则:构造方法必须与类同名,没有返回类型。
3、在创建的时候(new)对象时被自动调用。
4、注意:若自己不写构造方法,则编译器默认提供无参数的构造方法,若自己写了构造方法,则需要自己手动添加上去。构造方法不能同过点语法调用,只能在创建对象(new)的时候,被自动调用。
5、构造方法可以重载。
1、this用于指代当前对象,哪个对象调指的就是哪个对象,方法中访问成员变量之前默认有this。(this只能在方法中使用)。
2、this的用法:
1)this.成员变量名 →→→→→→访问成员变量
2)this.方法名()→→→→→→调用方法 (实用性,很低。几乎不用)
3)this()→→→→→→→→→调用构造方法
Class Cell{
Int row;
Int col;
Cell(int row,int col){
This.row = row1;//在局部变量和成员变量同名的时候。必须使用成员变量来区分。
This.col = col1;
}
Void drop(){
This.row++; //可以省咯this
}
}
Class Cell(){
int row;
int col;
Cell(){
This(0);
}
Cell(int n){
This(n,n);
}
Cell(introw,int col){
This.row = row;
This.col = col;
}
}
Cell o1 =new Cell(); //调用无参的构造方法
Cell o2 =new Cell(1); //调用一个参数的构造方法
Cell o2 =new Cell(1,2); //调用两个参数的构造方法
Cell 02 =new Cell(1,2,3); //编译错误,没有三个参数的构造方法
1、数组属于引用数据类型;
2、概念:数组对象在堆中存储,数组变量属于引用类型,存储数组对象的地址信息,指向数组对象。
3、数组的元素可以看成数据对象的成员变量(只不过类型全部相同)。
//声明int类数组arr,包含3个元素。
//每个元素都是int型,默认值为0。
int [] arr= new int[3];
arr[0] = →→→→int类型(基础数据类型)
arr[0] = 5;
int a = 5;
//声明Cell类数组cells,包含4个元素
//每个元素都是Cell型,默认值为null
Cell[]cells = new Cell[4]; //创建Cell数组对象
cells[0] →→→→Cell类型(引用类型)
cells[0] =new Cell(2,5); //创建cell对象
cells c =new Cell(2,5);
Cell[]cells = new Cell[4];
cells[0] =new Cell(2,5);
cells[1] =new Cell(3,6);
cells[2] =new Cell(4,8);
cells[3] =new Cell(5,10);
Cell[]cells = new Cell[]{
new Cell(2,4),
new Cell(3,6),
new Cell(4,8),
new Cell(5,10)
};
//声明int[] 型数组arr,包含3个元素
//每个元素都是int[]型,默认值为
Int[][] arr= new int[3][];
arr[0] →→→→→→int[] 型
arr[0] =new int[2];
arr[1] =new int[3];
arr[2] =new int[2];
给arr中第二2个元素中的第1个元素赋值为100。
Int[][] arr= new int[3][4];
For(int I =0 ; I < arr.length; i++){
For(int j = 0; j < arr[i].length;j++){
Arr[i][j] = 100;
}
}
基础数据类型和引用类型数组的区别:
1、基础数据类型数组可以直接赋值,引用类型数组需要通过new关键字创建对象,再通过构造函数进行赋值。(new Cell(3,5));
总结:
1)方法的标签名:方法名+参数列表
2)方法的重载(Overload):
a) 同一个类中,方法名称相同,参数列表不同。
b) 编译器在编译时自动根据方法的签名来绑定调用
3)构造方法(构造器、构建器、构造函数):
a) 常常用于给成员变量赋初始值。
b) 与类同名,没有返回类型。
c) 在创建(new)对象时被自动调用。
d) 若自己不写构造方法,则编译器默认提供无参构造方法,若自己写了构造,则不再默认提供。
e) 构造方法可以重载。
4)This:指代当前对象,那个对象调指的就是哪个对象。方法中访问成员变量之前默认都有个this。
a) This的用法:
i. This.成员变量 →→→→ 访问成员变量
ii. This.方法名 →→→→→调用方法
iii. This()→→→→→→→→调用构造方法
1、内存管理:由JVM来管理。
1)堆:
A)用于存储所有new出来的对象(包括成员变量)。
B)成员变量的声明周期:
创建(new)对象时存在堆中,对象被gc回收时一并消失。
C)垃圾回收器(GC)不定时到堆中扫描,扫描到垃圾则自动回收。
垃圾:没有任何引用所指向的对象。
回收的过程是透明的,并不是一看到垃圾就马上回收。
若想快速回收,可以调用System.gc();
D)内存泄露:不再使用的对象没有被及时的回收。
建议:当对象不再使用的时候应及时设置为null。
2、JVM在其内存空间开辟一个称为“堆”的存储空间。
1. 这部分空间用于存储使用new关键字所创建的对象。
2. Cell c = new Cell();成员变量存储在堆中,并且有默认值。
3. 例子:java程序运行,报内存不足。给电脑买内存条,装以后并没有解决问题。是因为java程序内粗是有JVM(虚拟机)管理的。装到电脑的内存条并没有装到JVM中。
垃圾是没有任何引用指向的对象。
3、栈:
1)用于存储正在调用中方法的所有局部变量。
2)调用方法时在栈中为该方法分配一块对应的栈桢,
栈桢中包含所有的局部变量(包含参数),
方法调用结束时,栈桢消失,局部变量一并消失。
3)局部变量的声明周期:
调用方法时存在栈中,方法调用结束时与栈桢一并消失。
1)成员变量:
a) 类中,方法外。
b) new时存在堆中,对象被回收时消失。
c) 有默认值。
2)局部变量:
a) 方法中。
b) 调用方法时存在栈中,方法调用结束时与栈桢一并消失。
c) 没有默认值。
Class Aoo{
Int a ; //成员变量有默认值
Void show(){
Intb; //局部变量没有默认值
System.out.println(a);
System.out.println(b);//编译错误
}
}
Aoo o = new Aoo();4、方法区
1)用于存储字节码文件.class字节码文件(包括方法)。
2)方法只有一份(只在方法区装载一次)。
Class Cell{
Int row;
Int col;
Void drop(){
Row++;
}
}
每个对象有自己对应的row和col。
所有对象共享一个drop()方法。
Cell c1 = new Cell();
C1.row = 2;
C1.col = 5;
Cell c2 = new Cell();
C2 .row = 1;
C2.col = 6;
1、目的:避免代码重复,有利于代码的重用。
2、通关extends 关键字了实现继承。示例:子类名 extends 父类名。
3、父类:所有子类所共有的的属性和行为。子类:子类所特有的属性和行为。
4、子类继承父类之后,子类具有:子类 + 父类。
5、 在java中只支持单一继承,一个父类可以有多个子类,一个子类只能有一个父类 →→→ 单一继承。示例:Student extendsperson,Aoo{} //错误
6、继承具有传递性。
Class Aoo{int a;} class Boo extends Aoo{int b;} class Coo extendsBoo{int c}
Coo o = new Coo(); o.c = 1; o.b = 2; o.a = 3; //传递性
1、 java规定:构造子类之前必须先构造父类。
a) 在子类中若没有调用父类的构造方法,则默认super()来调用父类的无参构造。若自己调了,则不在默认提供。
b) Super()调用父类构造方法,必须位于子类构造的第一句。
Class Person{Stringname; int age; String address; void eat(){} void sleep(){}}
ClassStudent extendsPerson{String ClassName; void study(){}}
ClassTeacherextends Person{double salary; void teach(){} }
ClassDoctor extendsPerson{String level; void cut(){} }
1、super:指点当前对象的父类引用。
2、用法:
Super.成员变量名 →→→→→访问父类的成员变量。
Super.方法名()→→→→→→→调用父类的方法。
Super()→→→→→→→→→→调用父类的构造方法。指向父类的引用。
• 通过关键字super我们可以指定子类在构造时调用父类的哪个构造器, 达到先实例化父类然后实例化子类的目的。
• 子类的构造器默认的调用父类无参构造器,即子类构造器中没有用super指明调用父类哪个构造器的话,实际上编译器会自动的在子类构 造器第一行加入代码super( );
1、父类型的引用指向子类的对象。
2、能点出来什么,看引用的类型。
3、总结:向上造型即允许一种类型有不同的实现,要注意重写父类方法返回值和访问权限的问题。要注意父类是不可以访问子类对象的属性或方法的。
4、在程序语言中,通过子类继承父类,然后重写覆盖的方法,在创建对象时,将父类的引用指向子类的对象,就可以利用父类引用调用子类的方法,从而实现“谁使用谁去实现”,也就是多态。
//动物是动物
Animal o1 = new Animal();
//老虎是老虎
Tiger o2 =new Tiger();
//老虎是动物
Animal o3 =new Tiger(); //向上造型
Class Animal{}
Class Tigerextends Animal{}
复习:
1、内存管理:堆、栈、方法区
2、继承:
避免代码重复,有利于代码的重用。
extends
父:共有的 子:特有的
子继承父,子具有:父+子
单一继承,传递性
构造子之前必须先构造父,自构造若不写,则默认super()调用父类的无参构造函数,则自己写了,则不再默认提供
3、super:指代当前对象的父亲对象
Super.成员变量名
Super.方法名()
Super() 表示调用父类的构造函数
4、向上造型
1)父类引用指向子类的对象
2)能点出来什么,看引用的类型
Student zs= new Student();
zs.name ="zhangsan";
zs.age =25;
zs.address= "湖南";
zs.className= "JSD1604";
zs.sayHi();//zhangsan,25,湖南,JSD1604 (重写后)
Teacherwhj = new Teacher();
wkj.name ="wangkejing";
wkj.age =37;
wkj.address= "内蒙古";
wkj.salary= 5000;
wkj.sayHi();//wangkejing,37,内蒙古 (没有重写)
Doctor doc= new Doctor();
doc.name ="lisi";
doc.age =45;
doc.address= "广州";
doc.level ="主治医师";
doc.sayHi();//lisi,45,广州 (没有重写)
以上三个对象,都继承冷Person(人类),子类继承父类,
子类:父类(共有)+子类(特有的)。每个子类对象调用
父类的sayHi() 只能输出姓名,年龄,地址这些父类方法内
的数据,不能输出子类特有的数据信息。父类的方法不够好,
子类可以进行改造,这就是方法的重写。
注意:重写方法被调用时,看对象的类型:
Person pl =new Student();
pl.sayHi();//调用的方法是Student的
//人类
classPerson{
String name; //姓名
int age; //年龄
String address; //地址
void sayHi(){
System.out.println(name+","+age+","+address);
}
}
//学生
classStudent extends Person{
String className; //类名
void sayHi(){
System.out.println(name+","+age+","+address+","+className);
}
}
//教师
classTeacher extends Person{
double salary; //工资
}
//医生
classDoctor extends Person{
String level; //水平
}
1、发生在父子类中,方法名相同,参数列表相同,方法体不同。
2、重写的方法被调用时,看对象的类型。
3、子类可以重写(覆盖)继承自父类的方法即方法名和参数列表与父类的方法相同;但方法的实现不同。
4、当子类对象的重写方法被调用时(无论是通过子类的引用调用还是通过父类的引用调用),运行的是子类的重写后的版本。
class Foo{
public void f(){
System.out.println("Foo.f()");
}
}
Class Gooextends Foo{
public void f(){
System.out.pirntln("Goo.f()");
}
}
Goo obj1 =new Goo();
obj1.f();
Foo obj2 =new Goo();
boj2.f();
输出的结果均为:Goof.f();
当子类对象的重写方法被调用时,(无论是通过子类的引用调用还是通过父类的引用调用),运行的是子类重写的版本。
class Foo{
public void f(){
System.out.println("Foo.f()");
}
}
Class Gooextends Foo{
public void f(){
super.f(); //调用父类的方法
System.out.pirntln("Goo.f()");
}
}
Foo obj2 =new Goo();
boj2.f();
输出的结果均为:Foo.f(); Goof.f();
子类重写方法中的super.f();调用父类的版本;这样的语法通常用于子类的重写方法在父类方法的基础之上进行功能扩展。
例如:我继承一个饭店(中餐)
→ →还是中餐(不需要重写)
→ →改为西餐(重写)
→ →中餐再加上西餐(先super并重写)
重写需要遵循"两同两小一大"原则:一般都是一模一样的
1.两同:
1)方法名称相同
2)参数列表相同
2.两小
1)子类的返回值类型小于等于父类的。
类型从小到大依次为:
byte,short,int,long,float,double
char
1.1)void 和 基本类型时,必须相同。
1.2)
//父类
classCoo{
void sayHi(){}
double show(){return 0.0}
Coo test(){return null}
Doo say(){return null}
}
//子类
classDoo extends Coo{
void sayHi(){} //void 时必须相同
double show(){return 1.1} //基本类型时必须相同
Doo test(){return null} //小于父类
Coo say(){return null} //编译错误,引用类型时候必须小于或等于
}
2)子类抛出的异常小于或等于父类的---异常
3.一大
1)子类方法的访问权限大于或等于父类的---访问权限修饰符。
1)重写:父子类中,方法名相同,参数列表相同
遵循"运行期"绑定,根据对象的类型调用,那个方法。
2)重载:一个类中,方法名相同,参数列表不同
遵循"编译期"绑定,根据引用的类型绑定,那个方法。
//方法的重载
class Goo{
void test(Eoo o){
System.out.println("父型参数");
o.show();
}
void test(Foo o){
System.out.println("子型参数");
o.show();
}
}
//方法的重写
class Eoo{
void show(){
System.out.println("父类");
}
}
class Fooextends Eoo{
void show(){
System.out.println("子类");
}
}
//重载看引用,重写看对象
Goo goo =new Goo();
Eoo o = newFoo(); //子类对象指向父类引用,向上造型
goo.test(o);//调用Goo类内的方法,而Goo的方法是重载看引用,传递过去的参数是Foo类型的,
匹配到第二个方法,先输出“子型参数”,o 是Foo类型的,属于重写,重写看对象,所以输出 “子类”。
1、定义类时需要指定类的名称,但如果仅仅将类名作为类的唯一标识符,
则不可避免的出现命名冲突的问题,这会给组件复用以及团队之间的合作
造成很大的麻烦!
2、在java语言中,用(package)的概念来解决命名冲突的问题,在定义
一个类时,除了定义类名的名称一般还要指定一个包名,定义包名的语法
为package报名;
例如:package teset;
class Point{}
3、package语句必须写在java源文件的最开始,在类定义之前,例如:下面
的语句将为Point类指定包名为"test":一旦使用的package指定了包名,类的全程
应该是"包名.类名"。例如,上述的Ponint类的全称是test.Point。不同的包可以定义相同的类名,例如:test1.Point和test2.Point是两个截然不同的名称。
总结:package
1)作用:避免类的命名冲突
2)包名可以层次结构
3)建议:包名所有字母都小写
4)类的完全限定名:包名.类名
注意:项目非常大的时候,建议:域名反写.项目名称.模块名称.类名
cn.tedu .manager .stumanager.Student
import:
1)作用:声明类/引入类
2)同包中的类可以直接访问
不同包中的类想访问:
2.1)先import声明类再访问类(建议)
importjava.util.Scanner; //声明Scanner类
2.2)类的全称-- 太繁琐(不建议)
o.d.b.c.s.a.Student
importoo.day04.*;(*通配符,代表所有。不建议使用因为会影响效率)
1、在设计类的时候,数据私有化(private)、行为公开化(public)
class Card{
private String cardId;//卡号
private String cardPwd;//密码
private double balance; //余额
puclic boolean payMoney(double money){ //支付
if(balance>=money){
balanece-=money;
return true;
}
return false
}
public boolean checkPwd(String pwd){ //检查密码
if(carPwd.equals(pwd)){
return true;
}
return false;
}
}
将卡号、密码、余额私有不可以访问,提供公开化的行为,对数据进行操作。
这样保护的数据的安全性,又提供了可操作的方法。
意义:
1)对外提供了可调用的、稳定的动能;
2)封装容易变化的、具体的实现细节,外界不可访问,这样的意义在于;
-降低代码出错的可能性,便于维护;
-当内部的实现细节改变时,只要保证对外的功能定义不变,其他的模块 就不会因此受到牵连。
2、public和private
1)private修饰的成员变量和方法仅仅只能在本类中调用。
2)public修饰的成员变量和方法可以在任何地方调用。
3)public修饰的内容是对外提供可以被调用的功能,需要相对稳定;private修饰的内容是对内实现的封装,如果"公开"会增加维护成本。
public class Point{
private int x;
private int y;
Point(int x,int y){
public int distance(Pointp){}
}
}
3、protected和default默认访问控制
1)用protected修饰的成员变量和方法可以被子类及统一包的类使用。
2)default默认访问控制即不书写任何访问控制符。默认访问控制的成员变量和方法可以同一个包中的类调用。
4、总结:
1)public:公开的,任何类。
2)private:私有的,本类。
3)protected:受保护的,本类、子类、同包类。
4)default默认的:什么也不写,本类、同包类。
对于类的修饰可以使用public和default默认方式。public修饰的类可以被任何一个类使用;默认访问控制的类只可以被同一个包中的类使用。
类成员的访问修饰:如上4中都可以。
protected和private可以用于修饰内部类。
1、补充知识点:
1)成员变量:
1.1)实例变量:
1.1.1)属于对象的,存在堆中。
1.1.2)有几个对象就有几个实例变量。
1.1.3)必须通过对象名,来访问。
1.2)静态变量:
1.2.1)属于类的,存在方法区中。
1.2.2)只有一份
1.2.3)常常通过类名.来访问
2、static:静态的
1)静态变量:
1.1)由static修饰
1.2)属于类的,存在方法区中,只有一份。
1.3)常常通过类名. 来访问。(对象点.来访问也可以,不建议)
1.4)何时用:所有对象的数据都一样时使用。
Studentls = new Student();
ls.className= "JSD1604" //因为数据相同,直接使用static不同一个赋值
Student.className= "JSD1604"; //使用Static修饰的变量,用类名.变量名 来访问。
//所有编码都一样,所有对象数据相同时使用static
classStudent{
String name; //姓名
int age; //年龄
String address; //地址
static StringclassName; //编号
}
3、静态方法:
3.1)由static修饰
3.2)属于类的,存在方法区中,只有一份
3.3)常常通过类名.来访问
3.4)没有隐式this的传递
静态方法中不能直接访问成员实例成员
2.5)何时用:方法的操作(方法体)仅参数相关而与对象无关时使用。
class Aoo{
int a; //实例变量--对象点来访问
static int b; //静态变量--类名点来访问
void show(){ //实例方法--隐式this
this.a++;
Aoo.b++;
}
static void test(){ //静态方法
//没有this就意味着没有对象,而实例变量必须通过对象点来访问,静态方法中不能直接访问实例成员。
a++; //编译错误
show(); //编译错误
Aoo.b++;
}
}
注意:
1)自己创建的类中方法不要加static因为加了static的
方法,实例变量没有隐式添加this。没有this就意味着没有
对象。而实例变量只能通过"对象.变量"访问。
2)和main方法并列的方法都要加static,因为main方法是用static
修饰的,用static修饰的方法没this,没有this就没有对象。所以
并列的方法如果不用static修饰,方法无法调用因为没有this。用
static修饰之后,就可以使用类名.方法名访问。
3)和main方法并列的方法没有加static还执着于用对象访问可以自己创建一个对象。来进行访问。例如:
CellTest ct = new CellTest();
ct.printWall(c);
实例变量用得多还是静态变量用得多---实例多
实例方法用得多还是静态变量用得多---实例多
4、静态块:
4.1)由static修饰
4.2)属于类的,类被加载期间自动执行,
类只能被加载一次,所以静态块也只执行一次。
4.3)何时用:常常用于加载静态资源。(图片、音频、视屏)例如:cs有游戏不可能每个人进入游戏,给一张地图,地图只有一份,所有人共享。如果每个人一份,服务器是无法装载的。
public static void main(Stringargs[]){
//类只能被加载一次,所以静态块也只执行一次。
Noo o3 = new Noo(); //静态块、 构造方法
Noo o4 = new Noo(); //构造方法
}
class Noo{
static{
System.out.println("静态块");
}
Noo(){
System.out.pritnln("构造方法");
}
}
1、修饰变量:变量不能被改变。final Int a = 10; int b = 20; a = b; //编译错误
2、修饰方法:方法不能被重写。
使用一个方法不能被重写的意义在于:防止子类在定义新方法时造成的“不经意”重写。
3、修饰类:类不能被继承。
JDK中的一些基础类库被定义为final的,例如:String、Math、Integer、Doubleden等等。
使一个类不能被继承的意义在于:可以保护类不被继承修改,可以控制滥用继承对系统造成的危害。
//演示final修饰类
class Roo{}
class Soo extends Roo{} //编译错误,final的类不能被继承
class Too{}
finalclass Uoo extends Too{} //正确final的类,能继承别的类
class Poo{ //演示final修饰方法
void show(){}
finalvoid test(){}
}
class Ooo extends Poo{ //演示final修饰变量:变量不能被改变
/*
* final修饰成员变量,两种方式初始化:
* 1)声明的同时初始化
* 2)构造方法中初始化
* final修饰局部变量,只要使用之前初始化即可:
*/
finalinta = 5; //声明同时初始化
finalintb;
Ooo(){
b = 8; //构造方法中初始化
}
void show(){
finalintc; //使用之前赋值即可,不用可以不赋值。
//a = 55; //编译错误,final的变量不能被改变
}
//void test(){} //编译错误,final的方法不能被重写
}
1、staic final修饰的成员变量称为成常量,必须声明同时初始化,不可被改变。
2、static、final常量会在编译器被替换,例如:
class Foo{
public static final int NUM = 100;
}
class Goo{
public static void main(String[]args){
System.out.println(Foo.NUM);
//代码编译时,会替换为:System.out.println(100);
}
}
※static final 常量Foo.NUM会在编译时被替换为常量值(100),在运行Goo类时,Foo类不需要被载入。在编译的时候,被替换为具体的值,效率高。
3.总结:
1)必须声明同初始化(赋值)
2)不能改变,通过类名点来访问
3)建议:常量名所有字母都大写
4)权限修饰符 static public 位置可以随意调换
public class StaticFinalDemo {
public static void main(String[]args){
System.out.println(Aoo.PI); //通过类名点进行访问
//Aoo.PI = 14159434; //编译错误,常量不能被改变
}
}
class Boo{
public static final int NUM = 5;
public static int count = 8; //静态静态变量
}
class Aoo{
public static final double PI =3.14159;
//public static final int NUM; //编译错误,被static、final必须声明并赋值
}
1)由abstract修饰
2)只有方法的定义,没有方法的实现(大括号都没);
public static void main(String[] args){
Shape a = new Shape(); //编译错误 抽象类不能被实例化
}
abstract class Shape{ //图形 抽象类--不完整
double c;
abstract double area(); //抽象方法--不完整
}
abstract class Square extedns Shape{
double c;
double area(){ //方形
double c; //周长
double area(){
return 0.0625*c*c;
}
}
}
abstract class Circle extedns Shape{ //圆形
double c;
double area(){
return 0.0796*c*c;
}
}
abstract class Six extedns Shape{ //六边形
double c;
double area(){
return 0.721*c*c;
}
}
1)由abstract修饰
2)包含抽象方法的类必须是抽象类
不包含抽象方法的类,也可以声明为抽象类。---纯属我乐意
3)抽象类不能被实例化
4)类中有abstract 方法,代表类是不完整的,在类前加上abstract,不完整的类是不能实例化的。
5)抽象类都是需要被继承的,子类:
5.1)重写所有的抽象方法--常用
5.2)也声明为抽象类 -- 不常用
6)抽象类的意义:
6.1)包含公共的属性和行为,被子所用共享--实现代码复用
6.2)为所有的子类提供一种公共的类型--向上造型
6.3)包含抽象方法:为子类提供一个统一的入口(父类中有抽象方法,子类继承父类,子类必须重复父类的抽象方法,否则也要声明为抽象类,声明为抽象类无法创建对象(没有意义))。
子类有不同的实现。
abstract class Shape{ //抽象类不完整
double c;
abstract double area(); //抽象方法--不完整
}
class Square extends Shape{
double area(){ //重写抽象方法--变不完整为完整
return 0.0625*c*c;
}
}
class Circle extends Shape{
double area(){
return 0.0796*c*c;
}
}
//代码重复,扩展性差,维护性差
需求:给我一组图形,找出这组图形的最大面积。
Square [] ss = new Square[3];
ss[0] = new Square(1);
ss[1] = new Square(2);
ss[2] = new Square(3);
Circle[] cs = new Circle[3];
cs[0] = new circle(1);
cs[1] = new circle(2);
cs[2] = new circle(3);
Six[] sixes = new Six[3];
sixes[0] = new Six[1];
sixes[1] = nwe Six[2];
sixes[2] = nwe Six[3];
1.找到你ss中最大面值sMax
2.找到cs中最大面积cMax
3.找到sMax与cMax的最大值max
4.找到sMax与cMax以及sixMax的最大值max
//代码复用、扩展性好、维护性好
//abstract 不能创建对象(new Shape()),但是能创建Shape数组对象
Shape[] shapes = new Shape[9]; //创建Shape数组对象
shapes[0] = new Squear(1); //向上造型
shapes[1] = new Squear(2);
shapes[2] = new Squear(3);
shapes[3] = new Circle(1);
shapes[4] = new Circle(2);
shapes[5] = new Circle(3);
shapes[6] = new Six(1);
shapes[7] = new Six(2);
shapes[8] = new Six(3);
//向上造型能点出来什么,引用类型。如果没有Shape父类的中的方法abstract class Shape(); 抽象类,没有方法的实现。得由子类继承并重写。也就是说abstract限制了子类的必须重写父类的方法,否则子类也必须声明为抽象类,否则无法创建对象。当子类重写父类的方法,也就出现了多态现象。一个方法多种实现方式。
double max = shapes[0].area(); //area方法的是double类型数据
for(int i = 0; i < shapes.length;i++){
double area = shapes[i].area();
if(area>max){
max= area;
}
}
System.out.println("最大面积为:"+max);
abstract class Shape{ //抽象类不完整
double c;
abstract double area(); //抽象方法--不完整 没有方法的实现
}
class Square extends Shape{
double area(){ //重写抽象方法--变不完整为完整
return 0.0625*c*c;
}
}
class Circle extends Shape{
double area(){
return 0.0796*c*c;
}
}
class Six extedns Shape{
double c;
double area(){
return 0.721*c*c;
}
}
※自己的理解:
abstract(抽象)修饰符,可以修饰类和方法
1,abstract修饰类,会使这个类成为一个抽象类,这个类将不能生成对象实例,但可以做为对象变量声明的类型,也就是编译时类型,抽象类就像当于一类的半成品,需要子类继承并覆盖其中的抽象方法。
2,abstract修饰方法,会使这个方法变成抽象方法,也就是只有声明(定义)而没有实现,实现部分以";"代替。需要子类继承实现(覆盖)。
注意:有抽象方法的类一定是抽象类。但是抽象类中不一定都是抽象方法,也可以全是具体方法。
abstract修饰符在修饰类时必须放在类名前。
abstract修饰方法就是要求其子类覆盖(实现)这个方法。调用时可以以多态方式调用子类覆盖(实现)后的方法,也就是说抽象方法必须在其子类中实现,除非子类本身也是抽象类。
注意:父类是抽象类,其中有抽象方法,那么子类继承父类,并把父类中的所有抽象方法都实现(覆盖)了,子类才有创建对象的实例的能力,否则子类也必须是抽象类。抽象类中可以有构造方法,是子类在构造子类对象时需要调用的父类(抽象类)的构造方法。
举个简单的例子下面有一个抽象类
abstract class E{
public abstract void show();//publicabstract 可以省略
}
然后其它类如果继承它通常为了实现它里面的方法
class F extends E{
void show(){
//写具体实现的代码
}
}
最后再主方法里面定义一个父类引用指向子类对象,就会发生多态现象,比如
E e=new F();
e.show();
实际调用了子类里面的show()方法
class Animal{ //动物
void run(){
在地上跑
}
}
class Tiger extends Animal{ //老虎
}
class Bird extends Animal{ //鸟
}
class Fish extends Animal{ //鱼
}
//Animal 父类中run方法,方法体{在地上跑},三个子类继承父类,老虎是在地上跑,鸟和鱼就不行了,所以写成抽象类,强制让子类重写run方法。
//run方法本来是没有意义的,但是加上abstract,就规定了只要是动物都得有这方法。而且必须重写符合自身行为的方法。(限制性)不重写必须加上abstract,那么不能实例化,就没有意义了,所以必须重写。
//是动物都能跑,但具体怎么跑,每个动物都不一样。
abstract class Animal{ //动物
abstract void run();
}
class Tiger extends Animal{ //老虎
voidrun();
}
class Bird extends Animal{ //鸟
void run();
}
class Fish extends Animal{ //鱼
void run();
}
※生活中的接口:
1)电脑厂商留的USB接口-----制定标准、规范
U盘、键盘、鼠标厂商-----遵守标准、规范
2)国家对开发商------------制定标准、规范
国家对家具厂商----------指定标准、规范
开发商、家具厂商--------遵守标准、规范
3)银行--------------------制定标准、规范
银行卡------------------遵守标准、规范
1、接口
1)概念:接口是一个标准、规范
遵守了这标准,就能干某件事----API之后就理解。
2)由interface定义
3)只能包含常量和抽象方法
interface Inter1{
public static final int NUM = 5;
public abstract void show();
double PI = 3.14159; //默认public static final
void sayHi(); //默认有public abstract
intnum; //编译错误,常量必须声明同时初始化
public void say(){} //编译错误,接口中方法默认是抽象方法,而抽象方法是没有方法的实现的
}
4)接口不能被实例化
5)接口也是需要被实现(继承)的,实现类(子类):
必须重写接口中的所有抽象方法。
interface Inter1{
vaid a(); //接口中的方法默认添加public
void b();
}
class Aoo implements Inter1{
public void a(){}; //实现接口的类中的方法,访问权限不能比父类小。
public void b(){};
}
6)一个可以实现多个接口,用逗号分隔
若又继承又实现时,应先继承extends后实现implements。
interface Inter1{
void a();
}
interface Inter2{
void b();
}
abstract class Aoo {
abstract void c(); //类中的方法权限修饰符不写就是默认的
}
class Boo extends Aoo implementsInter,Inter2{
public void a(){}
public void b(){}
void c(){} //子类继承父类,不写访问权限修饰符,根父类一样是默认的
}
7)接口可以继承接口
Inter1 o1; //正确
Inter1 o3 = new Inter1(); //错误,接口不能实例化
Inter2 o2 = new Aoo(); //正确,向上造型 可以造型为直接父类
Inter1 o4 = new Aoo(); //正确,向上造型 可以造型为间接父类
interface Inter1{
void a();
}
interface Inter2 extends Inter1{//Inter2 继承了Inter1
void b();
}
class Aoo implements Inter2{ //Aoo实现了Inter2 所以必须两个方法都实现,因为Inter2继承Inter1的所有东西
public void a(){}
public void b(){}
}
类对类----继承
接口对接口----继承
类和接口---实现
银行系统案例:
※接口是完全抽象的抽象类。
※接口是继承的单根性的扩张。
设计原则:
1、将公共的属性和行为封装到父类中
2、所有子类的行为都一样---普通方法
所有子类的行为不一样---抽象方法
3、若符合既是也原则时,使用接口实现。(既是什么也是什么)因为接口可以实现多个,类只能继承一个
教学总裁:
解决问题(),培训员工,编辑稿件()。
讲师:
解决问题(),培训员工,编辑稿件()
项目经理:
编辑稿件()
interface 企业顾问{
解决问题();
培训员工();
}
interface 技术图书作者{
void 编辑稿件();
}
abstractclass 职员{
姓名,年龄,工资
void 上班打卡(){}
void 下班打卡(){}
abstract void 完成本职工作(){}
}
class 教学副总裁 extends 职员 implements 企业顾问,技术图书作者{
}
calss 讲师 extends 职员 implements 企业顾问,技术图书作者{
}
class 项目经理 extends 职员 implements 技术图作者{
}
class 班主任 extends 职员{
}
多态:多种形态,例如:水、可以固态、液态、气态
1、意义:
1.1)同一类型的引用指向不同的对象时,有不同的实现----行为的多态。 eg:cut();
cut(); //剪
※在程序语言中,通过子类继承父类,然后重写覆盖的方法,在创建对象时,将父类的引用指向子类的对象,就可以利用父类引用调用子类的方法,从而实现“谁使用谁去实现”,也就是多态。
※同一类型的引用去指向不同的对象,有不同的实现。
人 p1 = new 理发师(); //向上造型
人 p2 = new 外科演员(); //向上造型
人 p3 = new 演员(); //向上造型
p1.cut(); //剪发
p2.cut(); //开刀
p3.cut(); //停止表演
abstract class 人{
abstract void cut();
}
class 理发师 extends 人{
void cut(){ 剪发 }
}
class 外科医生 extends 人{
void cut(){ 开刀 }
}
class 演员 extends 人{
void cut(){ 停止表演 }
}
1.2)同一对象被造型为不同的类型时,有不同的功能。----对象的多态:我,水
我 me = new 我();
讲师 p1 = nwe me;
孩子他妈 p2 = new me;
老公的老婆 p3 = new me;
p1.授课();
p2.揍他();
p3.咬他();
p3.收工资();
interface 讲师{
void 授课();
}
interface 孩子他妈{
void 揍他();
}
interface 老公的老婆{
void 咬他();
void 收工资();
}
class 我 implements 讲师,孩子他妈,老公的老婆{
public void 授课(){}
public void 揍他(){}
public void 要他(){}
public void 收工资(){}
}
2)向上造型:
2.1)父类型的引用指向子类的对象(引用是父类,对象是子类的)
2.2)能造型成的类型有:
父类型、实现的接口
2.3)能点出来什么,看引用的类型。
3)强制类型转换,成功条件有两个:
3.1)引用所指向的对象,就是该类型
3.2)引用所指向的对象,实现了该接口
父类大,子类小,其实就是将T类型赋值给Tetromino,所以说能点出来什么看引用类型
Tetromino o1 = new T(); //向上造型--自动类型转换
Aoo o1 = new Boo(); //向上造型
Boo o2 = (Boo)o1; //引用o1所指向的对象就是Boo,符合条件1
Inter1 o3 = (Inter1)o1; //引用o1所指向的对象,实现了Inter1这个接口,符合条件2
Coo o4 = (Coo)o1;//ClassCastException类型转换异常
if(o1 instanceof Coo){
Coo o4 = (Coo)o1;
}
interface Inter1{
}
class Aoo{
}
class Boo extends Aoo implementsInter1{
}
class Coo extends Aoo{
}
4)建议强制转换之前都通过instanceof来判断引用是否是某种类型
instanceof返回boolean结果
System.out.println(o1 instanceof Boo); //true
System.out.println(o1 instanceof Inter1); //true
System.out.println(o1 instanceof Coo); //false
if(o1 instanceof Coo){
Coo o4 = (Coo)o1;
}
注意: o1和Coo没有任何关系,不能使用instanceof来判断,否则编译时,直接报错。
Aoo o1 = new Aoo();
if(o1 instanceof Coo){
Coo o5 = (Coo)o1;
}
class Aoo{
}
class Coo{
}
1)成员内部类:不太常用
1.1)类中套类,外面的叫外部类,里面的叫内部类
1.2)内部类通常只服务于外部类,对外不具备可见性
1.3)内部类对象通常是在外部类中创建的,
1.4)内部类可以直接访问外部类的成员(包括私有private)
内部类中有个隐式的引用指向创建它的外部类对象
外部类.this.成员变量(方法)
class Test{
voidshow(){
Aooo1 = new Aoo(); //外部类
Booo2 = new Boo(); //编译错误、内部类--Aoo的一个成员(不是独立的)
}
}
classAoo{ //外部类
privateint a;
voidshow(){
Booo = new Boo(); //正确
}
classBoo{ //Boo就是成员内部类
voidtest(){
System.out.println(a);//正确、
//内部类中有个隐式的引用指向创建它的外部类对象
System.out.println(Aoo.this.a);//正确
//这的this.a代表当前对象,当前的对象Boo没有a这个成员变量所以编译错误
System.out.println(this.a); //编译错误
}
}
}
2)匿名内部类:比较常用
概念:定义匿内部类
如果在一段程序中需要创建一个类的对象(通常这个类需要实现某个接口或者继承某个类),而且对象创建后,这个类的价值就不存在了,这个类可以不必命名,称之为内部类。
2.1)如果想创建一个类的对象,并且对对象只被创建一次,此时该类不必命名,称为匿名内部类
2.2)匿名内部类中访问外部数据,改数据必须final的
publicclass NstInnerClassDemo {
publicstaticvoid main(String[] args){
//1.创建了Inter2的一个子类,没有名字
//2.为该子类创建一个对象,引用叫o1
//3.大括号中的为子类的了类体
Inter2 o1 = new Inter2(){
};
//1.创建了Inter2的一个子类,没有名字
//2.为该子类创建一个对象,引用叫o1
//3.大括号中的为子类的了类体
Inter2 o2 = new Inter2(){
};
//o1跟o2不是一个对象,因为o1和o2是两匿名内部类,这做只是创建了Inter2的子类。
// Inter2 o2 = new Doo();
// Inter2 o3 = new Doo();
// Inter2 o4 = new Doo();
finalintnum = 5;
//1.创建了Inter2的一个子类,没有名字
//2.为该子类创建一个对象,引用叫o1
//3.大括号中的为子类的了类体
Inter3 o3 = new Inter3(){
publicvoid show(){
System.out.println("showshow");
System.out.println(num); //num需加final
}
};
o3.show();
}
}
interface Inter3{
publicvoid show();
}
class Doo implements Inter2{
}
interface Inter2{
}
※面试题内部类有自己的.class吗?
答:有
面向对象的三大特性:
1、封装:
1)类:封装的是对象的属性和行为
2)方法:封装的是具体的逻辑功能实现
3)访问控制修饰符:封装的是访问的权限
2、继承:
1)作用:避免代码重复,有利于代码的重用
2)父类:所有子类所共有的属性和行为
子类:子类所特有的属性和行为
3)子类继承(extends)父类后,子具有:父+子
4)传递性、单一继承、多接口实现
3、多态:
1)意义:行为的多态、对象的多态
2)向上造型、强制类型转换、instanceof
3)多态的表现形式:
重写+重载
重载:
System.out.println(5);
System.out.prinltn(5,7);
System.out.prinltn('你');
System.out.println(true);
System.out.println("helloWorld");
面向对象六天的内容:
第一天:
1、什么是类?什么是对象?
2、如果创建类?如果创建对象?
3、引用类型之间画等号
4、null和NullPointerException
第二天:
1、方法的重载
2、构造方法
3、this
4、引用类型数组
第三天;
1、内存管理:堆、栈、方法区
2、继承
3、super
4、向上造型
第四天:
1、方法的重写
2、重写与重载的区别
3、package和import
4、访问权限修饰符
5、static
6、static final常量
第五天:
1、抽象方法
2、抽象类
3、接口
第六天:
1、多态:意义、向上造型、强制转换、instanceof
2、内部类:成员内部类、匿名内部类
面向对象的三大特性:
1、封装:
1)类:封装的是对象的属性和行为
2)方法:封装的是具体的逻辑功能实现
3)访问控制修饰符:封装的是访问的权限
2、继承:
1)作用:避免代码重复,有利于代码的重用
2)父类:所有子类所共有的属性和行为
子类:子类所特有的属性和行为
3)子类继承(extends)父类后,子具有:父+子
4)传递性、单一继承、多接口实现
3、多态:
1)意义:行为的多态、对象的多态
2)向上造型、强制类型转换、instanceof
3)多态的表现形式:
重写+重载
重载:
System.out.println(5);
System.out.prinltn(5,7);
System.out.prinltn('你');
System.out.println(true);
System.out.println("helloWorld");
面向对象六天的内容:
第一天:
1、什么是类?什么是对象?
2、如果创建类?如果创建对象?
3、引用类型之间画等号
4、null和NullPointerException
第二天:
1、方法的重载
2、构造方法
3、this
4、引用类型数组
第三天;
1、内存管理:堆、栈、方法区
2、继承
3、super
4、向上造型
第四天:
1、方法的重写
2、重写与重载的区别
3、package和import
4、访问权限修饰符
5、static
6、static final常量
第五天:
1、抽象方法
2、抽象类
3、接口
第六天:
1、多态:意义、向上造型、强制转换、instanceof
2、内部类:成员内部类、匿名内部类
java中的调试Debug
写一段程序,本身会有一个预期的结果
需求----算法----运行:
1、与你想的结果一样
2、与你想的结果不一样----Debug
Debug:找到错误的出处
F5:逐步调试(进入到方法中)
F6:逐过程调试(不会进入到方法中)
F7:跳出当前的方法
F8:调到下一个断点,若没有下一个断点程序调试结束
如何看变量的值?如何添加监视(看表达式的值)?
1、局部变量:
局部变量的定义:定义在方法中的变量都是局部变量(main方法也是方法,所以定义在main方法中的变量也是局 部变量)。
生存时间:局部变量的生存时间和方法的生存时间一致,调用该方法声明该局部变量并初始化的时,该局部变量被创建并分配内存空间;直到该方法调用结束局部变量也就结束了;
是否需要初始化:局部变量在使用前必须进行初始化,系统默认不会对局部变量进行初始化数据操作,如果局部 变量在使用前没有进行初始化则会在编译器报错;如果局部变量进行了声明没有进行初始化, 但是也一直没有被使用的话编译也是不会报错的;(局部变量使用前必须初始化话)
创建位置: 局部变量是创建在栈内存中的;
2、全局变量:
2.1 非静态全局变量:
非静态全局变量的定义:非静态全局变量都是定在类中,是类的成员变量或者说是成员属性属于类的一部分(或 者说是对象的一部分);
生存时间:非静态全局变量加载在堆内存中,随着声明初始化而创建,随着对象消亡而消亡;
是否需要初始化:全局变量都是不需要被强制初始化的,系统都会默认根据其数据类型进行默认赋值;但是建议 在声明时都进行初始化操作;
创建位置:创建在堆内存中,因为非静态的全局变量数对象的成员变量是对象的一部分;
2.2静态全局变量:
静态全局变量的定义:静态的类成员变量;
生存时间:静态全局变量随着类的字节码文件加载而加载产生,随着字节码文件的消失而消失,生存时间比类的 对象还要长;
是否初始化:凡是全局变量都是可以不要初始化的,静态变量也是一样,系统会自动根据其数据类型进行赋默认值,但是建议变量在声明时都进行初始化;
创建位置:静态变量时存在于对内存中的,所以静态全局变量也是存在于堆内存中的;
1、单例模式:保证一个类只有一个实例,并提供一个访问它的全局访问点。
2、单例模式要点:
某个类只能有一个实例。
它必须自行创建这个实例。
必须自行向整个系统提供个实例。
3、单例模式实现:
拥有一个私有构造器
提供一个自身静态私有的成员变量
提供一个公有的静态公有的方法
publicclassSingletonClass {
//构造器私有
privateSingletonClass(){}
//提供一个静态的事例变量
privatestatic SingletonClass instance;
//提供一个本类的实例的方法
publicstatic SingletonClassgetInstance(){
if(instance == null){
instance = new SingletonClass();
}
returninstance;
}
}
publicclassTest {
publicstaticvoid main(String[] args){
SingletonClass a =SingletonClass.getInstance();
SingletonClass c =SingletonClass.getInstance();
System.out.println(a==c);
}
}
2.1)Object类的直接子类Throwable描述了所有被虚拟机抛出的非正常状况。一般情况下很少使用Throwable,而是使用它的两个子类Error、Exception。
2.2)Error类特指应用程序在运行期间发生的严重错误。如:虚拟机内存用尽、堆栈溢出等等。一般情况下这种错误都是灾难性的,所以没有必要用异常处理机制处理Error。
2.3)Exception类有十几个子类,描述了不同的异常,其中:
2.3.1)以RuntimeException为代表的一些类,称为非检查性异常、
2.3.2)以IOException为代表的一些类为检查性异常。所谓的检查和非检查是指编译器在编译时是否检查。如果代码中存在检查性异常,必须进行异常处理,否则编译时不能通过;而非检查性异常编译时不进行检查,到运行时才会显示。
3.1)检查性异常:
若系统运行时可能产生该类异常,则必须写出相应的处理代码,否则无法通过编译。
非RuntimeException(运行异常)异常。
3.2)非检查性异常
若系统运行时可能产生该类异常,则不必在程序中声明对该类异常的处理,就可以编译执行。
RuntimeException:运行时异常
4.1)一般我们不在代码中处理非检查性异常,这类异常都运行时抛出。原因主要是由于程序员经验不足或是思维不缜密造成。如:数组越界、整数除以0等,这类异常起始就我们通常说bug。所以,这类异常应通过反复测试尽量避免,而不应该靠异常处理机制来解决。
4.2)检查性异常不同,就程序员再有经验,也是难以避免。如:用户链接数据库的异常,如果由于数据库服务器没有启动或是网络中断引起的,我们程序员是无法避免的。又如:程序要读取光盘中的文件,而用户忘记插入光盘,此时跑出文件没有找到异常,程序员也无法避免。
4.3)综上所述,异常处理机制主要处理检查性异常而不是非检查异常和Error。
5.1)抛出异常 → 捕获异常 → 处理异常
5.2)原理:在java程序执行过程中如果出现异常事件,系统会发出异常报告,这时系统生成一个异常对象,异常类对象封装了异常事件的信息并将其提交个java运行时系统。
5.3)处理异常的两种方式:
5.3.1)自行处理:可能引发异常的语句封入在try块内,而处理异常的想应语句则封入在catch块内。
5.3.2)回避异常:在方法声明中包含throws字句,通知潜在调用者,如果发生了异常,必须由调用者处理。
public class excption_sample{
publicstatic void main(String args[]){
inti = 0;
Stringgreetings[] = {"Hello World","Hello Dingdang","HelloKitty"};
//try{}表示可能发生异常的语句
try{
while(i<4){
System.out.println(greetings[i]);
}
//Catch()内的参数异常类对象的声明
}catch(ArrayIndexOutOfBoundsExceptione){
//catch{}内的语句是对异常的处理
System.out.println("数组越界异常");
}
}
}
6.1)try..catch语句
6.1.1)catch块,是用捕获并处理try块抛出的异常的代码块。没有try块,catch块不能单独存在。我们可以有多个catch块,以捕获不同类型的异常。
6.1.2)如果程序抛出多个不同类型的异常,我们需要多个catch()语句来处理。
6.1.3)和特殊异常类相关联的atch块必须写在和普通异常类相关联的catch()之前。
6.1.4)try{… }和catch(){…} 之间可不添加任何语句。
try(){
}catch(ArrayIndexOutOfBoundsExceptione){
System.out.println("Outof Bounds!");
}catch(RuntimeException e){
System.out.println("runtimeException!");
}catch(Exception e){
System.out.println("Exception!");
}
6.2)每次try块有异常跑出,系统会试着从上到下往每个catch块中传参,值到遇到一个类型匹配的catch块为止。
6.2.1)如上示例中最后一个catch块中的形参为Exception类型,它是所有异常的父类,任何异常都可以传参到该块中,该块可以处理任何类型的异常。因此,这个catch块只能放到最后面,否则所有的异常都被处理了,其他的catch块就不能分门别类的起作用了。
7.1)finally语句放在try..catch 语句后
7.2)finally 语句中的代码块不管异常是否被捕获总是要执行。
7.3)作用:通常finally语句中可以进行资源的清除操作,如:关闭打开文件、删除临时文件。
7.4)对应finally代码中的语句,及时try代码块和catch代码块中使用了return语句退出当前方法或break跳出某个循环,相关的finally代码块都有执行。
7.5)当try或catch代码块中执行中执行了System.exit(0)时,finally代码中的内容不执行。
try(){
}catch(ArrayIndexOutOfBoundsExceptione){
System.out.println("Outof Bounds!");
}catch(RuntimeException e){
System.out.println("runtimeException!");
}catch(Exception e){
System.out.println("Exception!");
//无论是否捕获异常,系统都会执行该语句
}finally{
System.out.println("清场");
}
8.1)如果一个方法中的语句执行时可能生成某种异常,但是不能确定如果不处理,则可以在程序所在的函数声明后,使用throws关键字抛出异常。
class ThrowsDemo{
publicvoid proc() throwsIOException{
System.out.println("insideproc");
}
}
8.2)位置:函数参数列表的后面
8.3)throws关键字后面,可以跟多个异常,中间用逗号分隔
8.4)throws 关键字抛出的异常,由调用该函数的函数处理。
8.5)机制:
8.5.1)方法中如果用throws关键字抛出:
非检查性异常:上一级取出异常,至到不抛异常;
8.5.2)检查性异常:
※在调用该函数内try-catch,把异常处理掉。那么不往上一级抛出异常,程序正常执行,上一级方法并不知道曾经产生异常。
※用throws声明方法抛出异常,不进行处理。谁调用谁负责处理。
※覆盖(重写)方法抛出异常时,可以抛出与被覆盖方法相同的异常或者被覆盖异常的子类异常。
public class ThrowTest{
publicvoid createFile(String path) throws IOException{
Filef= new File(path);
f.createNewFile();
}
publicstatic void main(String[] args){
ThrowTesttt = new ThrowTest();
try{
tt.createFil("c:/abc.txt");
}catch(IOExceptionex){
ex.printStackTrace();
}
}
}
※异常是通过关键字throw抛出,程序可以用throw语句引发明确的异常。如:
9.1)throw语句用在方法体内,表示抛出异常,由方法体内的语句处理。不能单独使用,要么和try。。。catch 一起使用,要么throws一起使用。
9.2)throw语句的操作数一定是Throwable类类型或Throwable子类类型的一个对象。
10.1)方法调用堆栈:
※后进先出:方法A调用方法B的时候,只有方法B先完成后,方法A才完成。先执行的方法总是后完成,后执行的方法先完成。类似于数据结构中的堆栈—后进先出,我们称之为方法调用堆栈。
※就有一条语句抛出异常,会导致所有的方法都不能正常使用结束。如果不想出现这样的情况,我们就使用java的异常处理机制—抓抛模式。
11、自定异常类
11.1)如果java提供的异常类型不能满足程序设计的需要,我们可以定义自己的异常类型。
11.2)用户自定义的异常类应为Exception类(或者Exception 类的子类)的子类。
1、什么是JDK API
JDK中包含大量的API类库,所有API(Application Programming Interface,应用程序编程接口)就是一些写好、可提供直接调用的功能(在java语言中,这些功能以类的形式封装)。
2、JDK API包含的类库功能强大,经常使用的有:字符串操作、集合操作、文件 操作、输入输出操作、网络操作、多线程等等。
3、JDK包结构
3.1)为了便于使用和维护,JDK类库按照包结构划分,不同功能的类在不同的包中;
3.2) 经常使用的包如下表所示
包 |
功能 |
Java.lang(jvm默认自动导入) |
Java程序的基础类,如字符串、多线程等,该包中的类使用的频率非常高,不需要import,可以直接使用 |
Java.util |
常用的工具类,如集合、随机数产生器、日历、时钟等。 |
Java.io |
文件操作、输入、输出操作 |
Java.net |
网络操作 |
Java.math |
数学运算相关操作 |
Java.security |
安全相关的操作 |
Java.sql |
数据库访问 |
Java.text |
处理文字、日期、数字、信息的格式 |
4、文档注释规范
4.1)以/**开始,以*/结束;
4.2)加在类和方法的开头,用于说明作者,时间,版本,要实现功能的详细描述等信息;
4.3)通过javadoc工具吗,可以轻松的将此注释转换为HTML文档说明;学习者和程序员主要通过文档了解API的功能;
4.4)文档注释不同于普通的注释(//..或/*…*/),普通注释写在程序之中,用于程序员进行代码维护和交流,无法通过工具生成文档;而文档注释(/**../)写在类和方法的开头,专门用于生成提供API使用者进行参考的文档资料。
5、生成API文档
1.1)java.lang.String使用了final修饰,不能被继承;
1.2)字符串底层封装了字符数组以及针对字符数组的操作算法。
1.3)字符串一旦创建,对象永远无法改变,但字符串引用可以重新赋值。(节省内存,但当new的时候一定会创建新对象)
1.4)java字符串在内存中采用Unicode编码方式,任何一个字符对应两个字节的长编码。
String s1 ="123abc";
String s2 ="123abc";
String s3 =new String("123abc");
System.out.println(s1==s2); //true //==是内存地址的比较,s1和s2指向同一内存地址所以结果为true
System.out.println(s1==s3); //s1 静态创建,s2 是通过new关键字动态创建的,通过new关键字创建的一定会创建新的对象,所以结果是false
System.out.println(s1.equals(s2));//返回结果是true 通过equals进行比较,是值之间的比较
s1=s1+"!"; //创建新对象,字符串创建后是不改变的,所以在内存原有的123abc并不会改变,而重新创建一个对象,让s1的引用重新指向
System.out.println(s1);
System.out.println(s2);
System.out.println(s1==s2); //输出结果为false,s1内存地址改变的了
※面试题
String s2 = "123abc";
String s4 = "123"+"abc";
System.out.println(s4==s2); //true
解析:编译器发现表达式两边都是字面量(定死的值),编译器做了一个手脚,它把程序编译成.class文件之前,就把“123”+“abc”计算好了,也就是说在生成.class文件之前,String s4 = “123abc”;那对于虚拟机来讲s2和s4内存地址一样的。
Stringstr1 = "123";
Stringstr2 = "abc";
Strings5 = str1 + str2;
System.out.println(s5==s2); //false
解析:编译器如果发现表达式的两边都是变量,那么在生成.class文件之前,和之后都是一样的。也就是说 Str1 + Str2 (之前),str1+str2(之后)。所以s5==s2结果为false
问这样会浪费性能吗?
int a =1+2;
解析:不会,因为程序在编译的时候,就已经计算好1+2的值。
问为什么要这样做?
解析:程序编译只有一次,执行是多次的。那么在能编译的计算出1+2的只,为什么还要在执行的时候再去计算这1+2的值的呢?所以说在程序运行的时候我们都是直接得到结果。
Ø 编译器的一个优化措施:当一个计算表达式符两边都是字面量时,会直接计算结果,然后将结果编译到class文件中,所以下边的代码在class文件中样子是:String s4 = “123abc”;
2.1)length();
String str = "我爱你java";
System.out.println(str.length());
2.2)indexOf(String str) 该方法使用来查找给定字符串在当前字符串中的位置。该方法有几个重载方法。
// 0123456789012345
String str = "thinkingin java";
//查找in在str字符串中的位置,若没有会返回-1
int index =str.indexOf("in");
System.out.println("index:"+index);
//重载方法允许从指定位置处开始查找
index = str.indexOf("in",2);
System.out.println("index:"+index);
//查找最后一次出现指定字符串的位置
index = str.lastIndexOf("in");
System.out.println("index:"+ index);
2.3)substring(int start,int end); 截取字符串,从指定位置(start)开始截取到指定的位置(end)。
Java api 有一个特点,通常用两个数字表示范围时,都是含头不含尾。
String str = "thinking injava";
//截取"ing"
String sub = str.substring(5,8);
System.out.println(sub);
//若只传入一个参数,这是从指定位置开始截取到末尾
String host = "www.tedu.cn";
sub = host.substring(4);
System.out.println(sub);
※面试题
编写一个程序,要求用户输入一个网址信息。
* 格式可是如下:
* www.baidu.com
* www.baidu.com.cn
* http:/www.baidu.com
* 然后经过处理,输出域名,如:baidu
Scanner scanner =new Scanner(System.in);
System.out.println("请输入一个网址");
String host =scanner.nextLine();
//获取第一个点之后第一个字符的位置
intstart = host.indexOf(".")+1;
//获取第二个点的位置
intend = host.indexOf(".",start);
String sub =host.substring(start,end);
System.out.println(sub);
2.4)String trim(); 去除当前字符串两边的空白字符
String str = " heloo ";
String trim = str.trim();
System.out.println(str);
System.out.println(trim);
2.5)char charAt(int index); 获取当前字符串指定下标对应的字符
String str ="thinking injava";
//查看第5个字符是什么?
charc = str.charAt(4);
System.out.println(c);
※检查字符串是否是回文
String info = "上海自来水来自海上";
booleanflag = true;
for(inti =0; i< info.length()/2;i++){
if(info.charAt(i) != info.charAt(info.length()-i-1)){
System.out.println("不是会文");
flag = false;
break;
}
}
if(flag){
System.out.println("是回文");
}
2.6)boolean startsWith(String str)boolean endsWith(String str) 判断当前字符串是否是以指定的字符串开始或结尾的。
Stringstr = "thinking in java";
//判断thi是否是str字符串的开头,必须连续,否则返回都为false
booleanstarts = str.startsWith("thi");
System.out.println("starts:"+starts);
booleanends = str.endsWith("ava");
System.out.println("ends:"+ends);
2.7)String toUpperCase() String toLowerCase() 将当前字符串的英文转换为全大写或全小写。
String str ="我爱java";
String upper =str.toUpperCase();
System.out.println(upper);
String lower =str.toLowerCase();
System.out.println(lower);
2.8) String 提供了若干重载的静态方法
Static String valueOf(xxx xxx)
该方法的作用是将java中其他类型转换为字符串
inta = 1;
StringstrA = String.valueOf(a);
System.out.println(strA);
doubled = 1.1;
StringstrB = String.valueOf(d);
System.out.println(strB);
4.1)StringBuilder提供了用于修改字符串内容的相关方法。
4.2)其内部维护的是一个可变的字符数组,所以修改都是在当前对象内部完成的。当频繁修改字符串内容时应该使用当前类来完成。
4.3)StringBuilder 常用方法
/**
*将String转换为StringBuilder
*可以使用有参的构造方法
*StringBuilder也有无参构造方法,默认表示空字符串
*/
String str ="努力学习java,";
StringBuilder builder =new StringBuilder(str);
/**
* 从StringBuilder转换为String
* 使用StringBuilder的toString方法即可
*/
str =builder.toString();
/**
*StringBuilder append(String str)
*向当前字符串末尾追加指定内容
*有若干重载方法,参数类型不同,这写重载方法允许追加其他内容(先转换为字符串再追加);
*
*努力学习java,为了找个好工作!
*/
//builder.append(1.1);
builder.append("为了找个好工作!");
System.out.println(builder);
/**
*
*StringBuilder replace(int start,int end,String str)
*将指定范围内的字符串替换为指定的内容。
*
*努力学习java,为了找个好工作!
*改为:
* 努力学习java,就是为改变世界!
*/
builder.replace(9,16, "就是为了改变世界");
System.out.println(builder.toString());
/**
*StringBuilder delete(int start,int end)
*将之前当前字符串中指定范围内的内容删除。
*
*努力学习java,为了找个好工作
*改为:
*,就是为了改变世界
*/
builder.delete(0,8);
System.out.println(builder.toString());
/**
*StringBuilder insert(int index,String str)
*将给定字符串插入到指定位置,原位置及后续字符串顺序向后移动。
*
*,就是为了改变世界!
*改为:
*活着,就是为了改变世界!
*/
builder.insert(0,"活着");
System.out.println(builder.toString());
/**
*反转字符串
*/
builder.reverse();
System.out.println(builder.toString());
//StringBuilder可以连着写,因为增删改查都是返回this对象。
builder.append("为了找个好工作!").reverse();
System.out.println(builder.toString());
5.1)StringBuilder是可变字符串。字符串的内容计算,建议采用StringBuilder实现,这样性能会好一些。
5.2)Java的字符串链接的过程是利用StringBuilder实现的
String s = “AB”; String s1 = s+”DE”+1;
String s1 = new StringBuilder(s).append(“DE”).append(1).toString();
5.3)StringBuffer 和StringBuilder
StringBuffer 是线程安全的,同步处理的,性能稍慢。
StringBuilder 是非线程安全的,并处理的,性能稍快。
字符集合 |
|
正则表达式 |
说明 |
[abc] |
a、b、c中任意一个字符 |
[^abc] |
除了a、b、c的任意字符 |
[a-z] |
a、b、c、…z中的任意一个字符 |
[a-zA-Z0-9] |
a-z、A-Z、0-9中任意一个字符 |
[a-z&&[^bc]] |
a-z中除了b和c以外的任意一个字符,其中&&表示“与”的关系 |
预定义字符集 |
|
正则表达式 |
说明 |
. |
任意一个字符 |
\d |
任意一个数字字符,相当于[0-9] |
\w |
单词字符,相当于[a-zA-Z0-9_] |
\s |
空白字符,相当于[\t\n\x0B\f\r] |
\D |
非数字字符 |
\W |
非单词字符 |
\S |
非空白字符 |
数量词 |
|
正则表达式 |
说明 |
X? |
表示0个或1个X |
X* |
表示0个或任意多个X |
X+ |
表示1个到任意多个X(大于等于1个X) |
X{n} |
表示n个x |
X{n, } |
表示n个到任意多个x(大于等于n个X) |
X{n,m} |
表示n个到m个X |
逻辑表达式 |
|
XY |
表示X后面跟着Y,这里X和Y分别是正则表达式的一部分 |
X|Y |
表示X或Y,比如"food|f"匹配的是foo(d或f),而"(food)|f"匹配的是food或f |
(X) |
子表达式,将X看做是一个整体 |
Boolean matches(String regex)
3.1)根据给定的正则表达式验证当前字符串是否满足格式
3.2)要求,满足则返回true,否则返回false
3.3)regex正则表达式。
3.4)正则表达式见到\的地方前面加个\
String regex ="[a-zA-Z0-9]+@[a-zA-Z0-9_]+(\\.[a-zA-Z0-9]+)+";
System.out.println(regex);
String mail = "[email protected]";
boolean flag = mail.matches(regex);
if(flag){
System.out.println("是邮箱");
}else{
System.out.println("不是邮箱");
}
System.out.println("请输入一个手机号码");
Scanner scanner = new Scanner(System.in);
String line = scanner.nextLine();
/**
*(\+86|0086)?\s*1[0-9]{10}
*/
String regex = "1[0-9]{10}";
if(line.matches(regex)){
System.out.println("是手机号");
}else{
System.out.println("不是手机号");
}
String[] split(String regex)
4.1)将当前字符串按照满足正则表达式的部分进行查分,返回拆分后的每段内容。
4.2)如果连续字符串连续匹配,那么将拆除空字符串,长度不减,但是如果在字符串的末尾,有连续字符匹配,则不会出现拆出空白字符的现象。
String str = "abc123def456ghi789jkl";
//按照数字拆分,保留所有的英文字母部分
String regex = "[0-9]+";
String[] array = str.split(regex);
//打桩
System.out.println("len:"+array.length);
for(int i = 0; i < array.length;i++){
System.out.println(array[i]);
}
4.3)图片重命名
/**
*System.currentTimeMillis() 获取系统当前的毫秒值
*/
String ingName = "1.jpg";
String names[] = ingName.split("\\.");
System.out.println(names[1]);
//符合条件的进行分割,1被分割到index为0,jpg被分配到index为1
ingName = System.currentTimeMillis()+"."+names[1];
System.out.println(ingName);
String replaceAll(String regex,String str)
5.1)将当前字符串中满足正则表达式的部分替换为给定的字符串
String str ="abc123def456ghi789jkl";
/**
* 将数字部分替换为“#NUMBER#”
*/
str = str.replaceAll("\\d","#NUMBER#");
System.out.println(str);
5.2)使用replaceAll实现图片重命名
String ingName = "1.jpg";
ingName = ingName.replaceAll("\\d","df");
System.out.println(ingName);
5.3)使用replaceAll实现和谐用语
//正则表达式
String regex ="(wqnmlgb|cnm|sb|2b|nc|tmd|cby|djb)";
String message = "wqnmlgb!你这个djb!你怎么这么的nc,你个2b!cnm!";
message = message.replaceAll(regex, "******");
System.out.println(message);
1.1)在java类继承结构中,java.lang.Object类位于顶端。
1.2)如果定义一个java类时没有extends关键字声明其父类,则其父类为java.lang.Object类。
1.3)Object定义了"对象"的基本行为,被子默认继承。
public class Foo{} 等价于 public class Foo extends Object{}
1.4)所以说Object是所有类的父类(基类/超类)
2.1)Object类中定义有toString方法,用于返回对象的字符串表示(一个可以表示该对象属性内容的字符串)。
2.2)所有的java类都继承了toString方法,Object类toString方法返回的字符串的形式为:类名@HashCode值。
Point p1 = new Point(1,2);
//转换之后得到引用的内存地址
Stringstr = p1.toString();
//day02.Point@15db9742
//包名.类名 .@十六进制哈希码值
System.out.println(str);
2.3)java类可以根据需要重写toString方法以返回更有意义的信息。
2.4)重写该方法后,返回的字符串没有严格的格式要求,将来可以根据需求而定。但是原则上该字符中应当包含当前对象信息。
2.5)只有我们自定义的类需要重写该方法,Java API提供的类通常都已经重写了该方法。
class Point{
privateint x;
privaetint y;
publicPoint(int x,int y){
this.x= x;
this.y= y;
}
//重写后的方法
publicString toString(){
return"("+x+","+y+")";
}
}
publicclass Test{
Pointp = new Point(1,2);
//输出的是给定对象toString返回的字符串
//System.out.println();方法,将返回的字符串输出。
System.out.println(p);
//没重写toString 方法时输出如:
//test.Point@5d888759
//重写toString后将输出
//x=1,y = 2
}
3.1)Object的equals方法用于对象的 "相等" 逻辑。
3.2)equals方法的定义在Object当中的:
publicboolean equals(Object obj)
equals方法的逻辑为:如果认为该方法的对象(this)与参数对象相等返回true,否则返回fasle
3.3)Object的equals方法的定义如下所示:
publicboolean equals(Object obj){
return(this== obj);
}
System.out.println(p1== p2); //内存地址的比较false 只有在内存指向相同对象才会相等
System.out.println(p1.equlasp2);//没有重写还是内存地址的比较false 没有重写只有在内存中指向相同地址才会相等
按照Object类eequals方法的逻辑,只有在this和obj是同一个对象时才返回true;java类可以根据需要重写继承自Object的equals方法。
3.4)java中== 和equals有什么区别?
答:1、==用于比较变量的值,可以应用于任何类型,如果用于引用类型,比较的是两个引用变量中存储的值(地址信息),判读两个变量的是否指向相同的对象;
2、equals是object的方法,重以后,可以用于比较两个对象的内容是否“相等”。
3、需要注意的是,Object默认的equals方法的比较规则同==
publicboolean equals(Object obj){
return(this == obj)
}
所以说Object中== 和 equals 是有任何的区别的。
但在String中,重写的equals方法是这样定义的:
publicboolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString =(String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
Long对象的equals的定义:
publicboolean equals(Object obj) {
if (obj instanceof Long) {
return value == ((Long)obj).longValue();
}
return false;
}
自己重写的类:
publicboolean equals(Object obj){
if(obj== null){
returnfalse;
}
if(obj== this){
returntrue;
}
if(objinstanceof Point){
Pointp = (Point)obj;
returnthis.x == p.x && this.y==p.y;
}
returnfalse;
}
※只有自己定义的类需要重写,Java API提供的类基本上都重写了equals
为什么有包装类的存在?
Java对于8个基本类型分别定义了对应的包装类,而包装类出现的原因是为了解决基本类型不能参与面向对象开发的问题。1、包装类是不可改变类,在构造了包装类对象后,不允许更改包装在其中的值;
2、包装类是final的,不能定义他们的子类。
基本类型 |
基本类型 |
父类 |
int |
Java.lang.Integer |
Java.lang.Number |
Long |
Java.lang.Long |
Java.lang.Number |
Double |
Java.lang.Double |
Java.lang.Number |
Short |
Java.lang.Short |
Java.lang.Number |
Float |
Java.lang.Float |
Java.lang.Number |
Byte |
Java.lang.Byte |
Java.lang.Number |
Char |
Java.lang.Character |
Java.lang.Object |
Boolean |
Java.lang.Boolean |
Java.lang.Object |
3、包装类和基础数据类型之间相互转换
3.1)基础数据类型可以通过,包装类构造器进行转换,或者是通过静态的valueOf方法进行转换。
3.2)包装类装转基础数据类型,可通过 类型Value(); 进行转换。
Integer o1 = new Integer(11);
Integer o2 = Integer.valueOf(12);
int i = o1.intValue();
4、最大值和最小值
4.1)数字类型包装类都支持两个常量:MAX_VALUE,MIN_VALUE分别保存了对应基本类型的最大值与最小值。
int imax = Integer.MAX_VALUE;
int imin = Integer.MIN_VALUE;
System.out.println("imax:"+imax);
System.out.println("imin:"+imin);
5、parseXXX(String str)
5.1)包装类提供了一个静态方法parseXXX(Stringstr) 可以将给定的字符串转换为对应的基本类型。前提是该字符串必须正确的描述基本类型可以保存的值。
String str = "123";
inti = Integer.parseInt(str);
6、自动拆装箱
6.1)从java 5.0版本以后加入到 autoboxing功能。
6.2)自动“拆箱”和“装箱”是依靠JDK5的编译在编译期“预处理”工作。
Integer a = 100; //装箱
Integer b =200; //装箱
Integer c = a + b; //拆箱再装箱
Double d = c; //拆箱
1、概述:java.Util.Date,Date的每一个实例用于表示一个确切的时间点。内部维护了一个long值,该值记录的是从:1970年1月1日 00:00:00 到表示的时间点之间所经历的毫秒值。整数是70年以后的日期,负数这是70年以前的日期。由于Date设计上存在缺陷(时区,千年虫),所以它的大部分方法被设置为“过时的”,不再建议使用。
1、java.text.SimpleDateFormat 根据一个给定的日期格式将String与Date相互转换。
注意:1、记住String和Date之间相互转换的方法
2、记住日期转换的格式。