黑色:标识符
蓝色:关键字
绿色:注释
红色:表示这个类是SUN公司的JDK写好的一个类。
凡是程序员自己有权力命名的单词都是标识符。
例如:类名;方法名;变量名;接口名;常量名…
但是!!!main不能更改
1,标识符只能由数字;字母(包括中文);下划线;美元符号¥组成。
2,标识符不能以数字开头
3,关键字不能作为标识符
4,标识符是严格区分大小写的:大写A与小写a是不一样的
5,理论上没有长度限
优点:有利于代码的可读性;让其它程序员更加容易理解。
1,见名知意(最好一看单词就能知道什么意思)
2,遵循驼峰命名方式(一高一低。例如:BiaoShiFuTest,一眼就能看出来意思)
3,类名,接口名特殊要求:首字母大写,后面每个单词首字母大写
4,变量名,方法名特殊要求:首字母小写,后面每个单词首字母大写
5,所有常量名:全部大写,并且单词与单词之间采用下划线_衔接
提前定义好了的一些具有特殊含义的单词。
这些单词全部小写,具有特殊含义,不能用作标识符
三要素:数据类型;变量名;值
类型决定空间大小
名字方便以后访问
值是变量保存的数据
变量声明: 数据类型 变量名;
变量分类:
在方法体内声明的变量称为**局部变量**;
在方法体外,类体中声明的变量称为**成员变量**;
注意:对于成员变量来说,没有手动赋值时,系统会默认赋值
变量作用域(变量的有效范围):
出了大括号就不认识了。
遵循就近原则:谁近访问谁。
作用:用来声明变量,为变量分配空间。
第一种:基本数据类型:
基本数据类型可以分为4大类8小种
四大类:
第一类:整数型
byte;short;int;long
第二类:浮点型
float;double
第三类:布尔型
boolean:只有false和true;false假,true真
第四类:字符型
char:必须用单引号括起来,属于文字
8小种:
byte;short;int;long
float;double
boolean
char
第二种数据类型:引用型数据类型
字符串型String属于引用数据类型
Java中除了基本数据类型外,其他的都是引用数据类型
引用数据类型后期面向对象才会接触
8种类型的区别:
所占空间不同
类型 占用字节数量(byte) 取值范围
byte 1 【-128 ~ 127】
short 2 【-32768 ~ 32767】
int 4 【-2147483648 ~ 2147483647】
long 8
folat 4
double 8
booleam 1
char 2 【0 ~ 65535】
关于计算机存储单位:
计算机只能识别二进制,(0001101100)
1字节 = 8bit ---> 1byte = 8bit
1KB = 1024byte
1MB = 1024KB
1GB = 1024MB
1TB = 1024GB
关于二进制(电脑中有计算机可以直接计算除进制,切换到程序员):
在计算机中,一个二进制最左边是符号位,为0表示正数,为1表示负数
二进制转化十进制:注意!!!遇到二进制0时,就是2的n次方*0
举例说明:(1111;1001)
1 1 1 1
2的3次方 2的2次方 2的1次方 2的0次方
8 4 2 1
8*1 + 4*1 + 2*1 + 1*1 = 15
-----------------------------------------------------------
1 0 0 1
2的3次方 2的2次方 2的1次方 2的0次方
8 4 2 1
8*1 + 4*0 + 2*0 + 1*1 = 9
十进制转换二进制:
该数除2;余数逆序输出。
字符编码是认为定义的一套转换表
在字符编码中规定了一系列的文字对应的二进制
字符编码是人为规定的。
‘a’--(采用二进制码进行编码)-->01100001
01100001--(采用ASCII码进行解码)-->‘a’
‘a’---->97
'b'---->98
......
'A'---->65
'B'----->66
......
'0'----->48(文字“0”)
国际标准组织制定了ISO-8859-1编码
中文编码方式:GB2312
注意!!!unicode编码是十六进制的。
前提:
计算机在任何情况下都只能识别二进制。
计算机在底层储存数据时,都是采用二进制补码形式,原因是:补码形式效率更高。
二进制有:原码,反码,补码
对于一个正数来说:二进制的原码,反码,补码是完全相同的。
例如:
byte i = 1;
对应的二进制原码:00000001
对应的二进制反码:00000001
对应的二进制补码:00000001
对于一个负数来说:二进制原码,反码,补码的关系是?
举例:
byte i = -1;
对应的二进制原码是:10000001
对应的二进制反码是(在原码基础上,符号位不变,其他位取反):11111110
对应的二进制补码是(在编译后的反码进行+1):11111111
在计算机中一个字节的最左边位为0时表示正数,为1时表示负数。
举例:
byte i = 150;
可以采用逆推导的方式推算出这个二进制补码对应的原码是啥。
该数二进制补码形式是:10010110
该数二进制反码形式是:10010101
该数二进制原码形式是:11101010
输出结果为:-106
'\t'是制表符,相当于键盘上的tab键。
'\n'是换行符
'\''表示普通的“'”单引号字符
'\\'表示普通的"\"反斜杠字符
'\"\"'表示普通的“""”双引号字符
class Test_LianXi2
{
public static void main(String[] arg){
//普通的‘t’字符
char c1 = 't';
System.out.println(c1);
//制表符‘\t‘相当于键盘的tad键
char c2 = '\t';
System.out.println("这个"+c2+"\\t是制表符");
System.out.println("这个\\t是制表符");
//’\n‘表示换行符。
char c3 = '\n';
System.out.println("这个\\n是换行符");//这行输出结果是换行两次
//'\''表示普通的“'”单引号字符
char c4 = '\'';
System.out.println("这个\\'表示普通的\"'\"单引号字符 ");
//'\"\"'表示普通的“"”双引号字符
char c5 = '\"';
System.out.println("这个"+"\\\""+"\\\""+"表示普通的“\"\"”双引号字符");
// '\\'表示普通的"\"反斜杠字符
char c6 = '\\';
System.out.println("这个\\表示普通的\"\\\"反斜杠字符");
//反斜杠u表示unicode编码
//unicode编码是十六进制的。
char c7 = '\u4e2d';
System.out.println(c7);
}
}
在Java中有一条非常重要的结论:
在任何情况下,整型的"字面量/数据"默认被当作int类型处理。
如果希望该”字面量/数据“被当作long类型来处理,需要在"字面量/数据"后面加"L/l"(大写L或者小写l)。
例题:
class Test_LianXi3
{
public static void main(String[]arg)
{
//214783647默认当作int来处理,这个数是int范围的最大值,
long a = 214783647;
System.out.println(a);
//214783648默认当作int来处理,但是超出了int范围,如果想要不报错只能在这个数后面+L;
long b = 214783648L;
System.out.println(b);
}
}
1,小容量可以直接赋值为大容量,被称为自动类型转换。
2,大容量不能直接赋值为小容量,必须加强制类型转换符进行强制转换。需要注意的是:加了强制类型转换符后,运行时可能会损失精度。
例题:
class Test_LianXi3
{
public static void main(String[]arg)
{
//将100赋值给c;默认当作int类型处理
int c = 100;
System.out.println(c);
//将c的值复制一份给d。
int d = c;
System.out.println(d);
//将200赋值给e,数据类型为long
long e = 200L;
//强制类型转换,将long类型转换为int类型
int f = (int)e;
System.out.println(f);
/*
300默认当作int类型处理,但是它超过了byte的最大取值范围,
这里想要运行通过,必须加强制类型转换符,但是会损失精度。
300这个int类型对应的二进制为:00000000 00000000 0000001 00101100
byte占用1个字节,砍掉前3个字节,结果是:00101100;转化为十进制则为44
所以最后输出结果为44
*/
byte a1 = (byte)300;
System.out.println(a1);
//100默认当作int类型处理,未超出byte的最大取值范围
byte a2 = 100;
System.out.println(a2);
}
}
当一个整数没有超出char;short;long的取值范围的时候,这个整数是可以直接赋值给char,short,long类型的变量。
当一个整数赋值给char类型变量的时候,会自动转换成charyuann字符型,最终输出结果是一个字符。
例外~!!!!char,short,long做混合运算时,会先转换为int类型再进行运算。
多种数据类型做混合运算时,最终结果类型是”最大容量“对应的类型(但是!!!上面char,short,long混合运算是例外)
举例:
class Test_LianXi4
{
public static void main(String[] arg)
{
//这里的a是ASCII码编译后的十进制数字97
char a1 = 'a';
long b = 2;
//先将a1,b转换为int类型后再进行运算,输出结果为99
System.out.println(a1 + b);
//a1,b转换为int类型后,再将其结果强制转换为short类型
short c = (short)(a1+b);
//输出结果为99
System.out.println(c);
}
}
1,float和double存储数据都是近似值。(有无限循环的小数,但是计算机内存有限无法储存。)
2,任意一个浮点型都比整数型空间大。
3,Java中规定,任何一个浮点型数据默认被当作double类型处理,如果要当做float处理,需要在字面量后面+F/f
4,当在财务系统等高精度领域软件使用时,通常不使用浮点型,使用java.math.BigDecimal(它是引用数据类型)
1,在Java语言中boolean类型只有两个值,没有其它值!!!
2,通常使用在逻辑运算中(充当条件)
第一条:八种数据类型中,除了boolean类型不能转换外,其它七种都可以进行转换
第二条:如果整数型字面量没有超出byte,short,char的取值范围,可以直接将其赋值为byte,short,char类型的变量。
第三条:小容量向大容量转换称为自动类型转换,容量从小到大的排序为:byte
重点掌握**++:自加1,–:自减1**
++可以出现在变量前也可以出现在变量后,++执行完之后,都会自加1
语法:当++出现在变量后,会先做赋值运算,再自加1
当++出现在变量前,会先自加1,再做赋值运算。
举例:
class Test_LianXi5
{
public static void main(String[] arg)
{
int a = 10;
//先进行赋值运算:将a=10赋值给b,即b=10,再进行a++,即a=11
int b = a++;
System.out.println(a);//输出结果为:11
System.out.println(b);//输出结果为:10
int c = 20;
//先进行++c运算:即c = 21,再进行赋值运算:即:d = 21;
int d = ++c;
System.out.println(c);//输出结果为:21
System.out.println(d);//输出结果为:21
int e = 30;
//这里的e++等同于:
//int e2 = e++;
//System.out.println(e2);
System.out.println(e++);//输出结果为30
System.out.println(e);//输出结果为31
int f = 40;
//这里的++f等同于:
//int f2 = ++f;
//System.out.println(f2);
System.out.println(++f);//输出结果为41
System.out.println(f);//输出结果为41
}
}
–:自减运算可以自己根据以上代码测试。
规则:
所有关系运算符的运算结果都是布尔类型,不是true就是false,不可能为其它值。
关系运算符中如果有两个符号,符号之间不能有空格。
举例:
class Test_LianXi6
{
public static void main(String[] arg)
{
int a = 10;
int b = 10;
System.out.println(a > b);//false
System.out.println(a < b);//false
System.out.println(a >= b);//true
System.out.println(a <= b);//true
System.out.println(a == b);//true
System.out.println(a != b);//false
}
}
&:逻辑与(并且):两边都是true,结果才是true
(不管第一个表达式结果是什么,第二个表达式一定会执行)
|:逻辑或(或者):有一边是true,结果就是true
(不管第一个表达式结果是什么,第二个表达式一定会执行)
!:逻辑非(取反):取相反的结果
&&:短路与:两边都是true,结果才是true;相比逻辑与&,效率高
(如果第一个表达式为false,第二个表达式不会执行)
||:短路或:有一边是true,结果就是true
(如果第一个表达式为true,第二个表达式不会执行)
特点:
逻辑运算符两边要求都是布尔类型,并且最终的运算结果也是布尔类型。
举例:
class Test_LianXi7
{
public static void main(String[] arg)
{
//只要有一边是false,那结果就是false.两个都是true,最终结果就为true
System.out.println(true & true);//true
System.out.println(true & false);//false
System.out.println(false & false);//false
System.out.println(100>90 & 100<110);//true
//只要有一边是true,那结果就是true,两个都是false,那结果就是false
System.out.println(true | true);//true
System.out.println(true | false);//true
System.out.println(false | false);//false
System.out.println(100>90 | 100>110);//true
//取反(不是...):
System.out.println(!true);//false;真的——》取相反的结果——》假
System.out.println(!false);//true;假的——》取相反的结果——》真
//这里100>110需要加括号,优先级问题
System.out.println(!(100>110));//true;100不大于110——》为假——》取相反的结果——》为真
int a = 10;
int b = 11;
//第一个表达式a>b结果为false,所以整个结果已经确定为false,但是它会继续执行第二个表达式a
System.out.println(a > b & a < b++);
System.out.println(b);//输出结果为12
//测试短路与&&
int c = 10;
int d = 11;
//使用短路与&&时,当第一个表达式为false,不会执行第二个表达式,这种现象被称为短路.
System.out.println(c > d && c < d++);
System.out.println(d);//输出结果为11
int aa = 10;
int bb = 11;
//第一个表达式a
System.out.println(aa < bb | aa > bb++);
System.out.println(bb);//输出结果为12
//测试短路或||
int cc = 10;
int dd = 11;
//使用短路或||时,当第一个表达式为true,不会执行第二个表达式,这种现象被称为短路或.
System.out.println(cc < dd || cc < dd++);
System.out.println(dd);//输出结果为11
}
}
1,包括基本赋值运算符和扩展赋值运算符
基本赋值运算符:=
扩展赋值运算符:+=,-=,*=,/=,%= (两个符号之间不能有空格)
使用扩展运算符时,永远不会改变变量类型。
探索:x +=10真的完全等同于x = x+10吗?
结论:不是完全等同。
举例说明:
class Test_LianXi8
{
public static void main(String[] arg)
{
int a = 10;
a += 10;//类似于a = a+10;但是本质上并不是完全相同
byte x = 100;//100没有超出byte的取值范围,可以直接赋值
System.out.println(x);//输出结果为100
//以下代码会编译报错:不兼容的类型———10+i是int类型,int类型不能直接赋值给byete类型变量x
//x = x+10; 编译报错
//这里的x +=10,等同于:x = (byte)(x + 10);强制类型转换。
x += 10;
System.out.println(x);//输出结果为110
byte y = 100;
y += 200;//由于相加后超出了byte取值范围,结果会自动损失精度
System.out.println(y);//输出结果为44
int i = 100;
i += 100;
System.out.println(i);//200
i -= 100;
System.out.println(i);//100
i *= 10;
System.out.println(i);//1000
i /= 10;
System.out.println(i);//100
i %= 30;
System.out.println(i);//10
}
}
语法格式:
布尔表达式 ? 表达式1 : 表达式2
执行原理:
当布尔表达式为true时,表达式1的结果作为整个表达式结果
当布尔表达式为false时,表达式2的结果作为整个表达式结果
举例:
class Test_LianXi9
{
public static void main(String[] arg)
{
boolean a = true;
//注意前面的数据类型需要根据表达式1和表达式2决定。
char b = a ? '男' : '女';
System.out.println(b);//输出男
//在println里面可以存放任何数据类型的变量
System.out.println(a ? '男' : '女');//输出结果:男
}
}
运算符:+
注意!!!
当 + 运算符两边的”任意一边“时字符串类型,那么这个 + 会进行字符串拼接操作。
遵循从左至右的顺序进行运算,出现括号,则先运算括号内的
口诀:
加一个双引号:”“,然后双引号中间加两个加号:”++“,然后两个加号中间加变量名”+变量名+“
分支语句,也叫条件语句。
if 语句格式:
一:if(布尔表达式){
java语句;
}
二:if(布尔表达式){
Java语句
}else{
Java语句
}
三:if(布尔表达式){
Java语句;
}else if(布尔表达式){ //分支
Java语句;
}...
四:if(布尔表达式){
Java语句;
}else if(布尔表达式){ //分支
Java语句;
}else{
Java语句;
}
注意:
1,对于if语句来说,在任何情况下只能有一个分支执行,并且执行后就表示if语句结束了。
2,只要是带有else分支的,一定会有一个分支执行,,没有else分支的可能会导致最后一个分支不执行。
3,控制语句之间是可以嵌套的,建议一个语句一个语句的进行分析,不要杂乱在一起分析。
class Test_if
{
public static void main(String[]arg)
{
java.util.Scanner s = new java.util.Scanner(System.in);
System.out.print("请输入您的年龄:");
int i = s.nextInt();
System.out.println();
/*if(i >= 0 && i <= 5){
System.out.println("幼儿");
}else if(i >= 6 && i <= 10){
System.out.println("少儿");
}else if(i >= 11 && i <= 18){
System.out.println("青年");
}else if(i >= 19 && i <= 45){
System.out.println("中年");
}else if(i >= 46 && i <= 150){
System.out.println("老年");
}else{
System.out.println("对不起,您已成仙!");
}*/
String str = "老年";
if(i >= 0 && i <= 5){
str = "幼儿";
}else if(i >= 6 && i <= 10){
str = "少儿";
}else if(i >= 11 && i <= 18){
str = "青年";
}else if(i >= 19 && i <= 45){
str = "中年";
}else{
str = "对不起,您已成仙!";
}
System.out.println(str);
}
}
class Test_if2
{
public static void main(String[] arg)
{
java.util.Scanner i = new java.util.Scanner(System.in);
System.out.print("请输入你的成绩:");
double score = i.nextDouble();
String str = "优秀";
if(score < 0 || score > 100)
{
str = "请输入0~100之间正确成绩!";
}else if(score < 60){
str = "不及格";
}else if(score < 70){
str = "及格";
}else if(score < 80){
str = "中等";
}else if(score < 90){
str = "良好";
}
System.out.println(str);
}
}
class Test_if3
{
public static void main(String[] arg)
{
java.util.Scanner s = new java.util.Scanner(System.in);
System.out.println("请输入天气所对应的数字:\n 1表示:雨天\t 0表示:晴天");
/*
boolean num1 = true;
boolean num0 = false;
num1 = 1;
num0 = 0;
*/
int weather = s.nextInt();
//System.out.println("您输入的天气是:"+ weather);
//System.out.println("您输入的性别是:"+ sex);
String str = "您所输入的数字有误。";
if(weather == 1){
System.out.println("请输入您的性别所对应的数字:\n 1表示:男\t 0表示:女");
int sex1 = s.nextInt();
if(sex1 == 1){
str = "男:打一把大黑伞";
}else if(sex1 == 0){
str = "女:打一把小花伞";
}else{
str = ("您所输入的数字有误。");
}
}else if(weather == 0){
System.out.println("请输入您的性别所对应的数字:\n 1表示:男\t 0表示:女");
int sex2 = s.nextInt();
if(sex2 == 1){
str = "男:直接走起";
}else if(sex2 == 0){
str = "女:涂防晒霜";
}else{
str = ("您所输入的数字有误。");
}
}else{
str = ("您所输入的数字有误。");
}System.out.println(str);
}
}
1,switch也是选择语句,又叫分支语句。
2,switch语法格式:
switch(值){
case 值1:
java语句;
...
break;
case 值2:
java语句
...
break;
default:
java语句;
}
其中break;语句不是必须的。default分支也不是必须的。
switch语句本质上支持int类型以及int类型的值,但是byte,char,short也可以使用(因为它们可以进行自动类型转换)。
技巧:
使用switch语句时,如果遇到数字较大的,可以先进行加减乘除,尽量让其的数字进行缩小,可以减少代码量,前提是不影响其最终效果。
class Test_Switch1
{
public static void main(String[] arg){
java.util.Scanner s = new java.util.Scanner(System.in);
System.out.println("请输入天气所对应的数字:\n 1表示:雨天\t 0表示:晴天");
int weather = s.nextInt();
//System.out.println("您输入的天气是:"+ weather);
//System.out.println("您输入的性别是:"+ sex);
String str = "男:打一把大黑伞";
switch(weather){
case 1:
System.out.println("请输入您的性别所对应的数字:\n 1表示:男\t 0表示:女");
int sex1 = s.nextInt();
switch(sex1){
case 1:
str = "男:打一把大黑伞";
break;
case 0:
str = "女:打一把小花伞";
break;
default:
str = "您输出的数字有误,请重新输入!";
}
break;
case 0:
System.out.println("请输入您的性别所对应的数字:\n 1表示:男\t 0表示:女");
int sex2 = s.nextInt();
switch(sex2){
case 1:
str = "男:直接走起";
break;
case 0:
str = "女:涂防晒霜";
break;
default:
str = "您输出的数字有误,请重新输入!";
}
break;
default:
str = "您输出的数字有误,请重新输入!";
}System.out.println(str);
}
}
class Test_Switch2
{
public static void main(String[] arg){
java.util.Scanner s = new java.util.Scanner(System.in);
System.out.println("请输入您的成绩(0~100)");
double score = s.nextDouble();
int grade = (int)score/10;//将double类型进行强制转换为int类型并赋值给grade
String str = "";
switch(grade){
case 0: case 1: case 2: case 3: case 4: case 5:
str = "不及格";
break;
case 6: case 7:
str = "及格";
break;
case 8:
str = "良好";
break;
case 9: case 10:
str = "优秀";
break;
default :
str = "请输入正确的成绩数字!";
}System.out.println(str);
}
}
语法:
for(初始化表达式;条件表达式;更新表达式){
循环体;
}
技巧:
for循环进行嵌套时,如果两个变量的条件相同,可以将嵌套内的循环变量 = 外循环变量。
经典例子:九九乘法表—1:共九行,1行1列,n行n列
代码:
class Test_Math2
{
public static void main(String[] arg){
for(int i = 1; i < 10 ; i ++ ){
for(int j = 1; j <= i; j++){
System.out.print(i+"*"+j+"="+i*j+"\t");//
}
System.out.println("");
}
}
}
语法:
while(布尔表达式){
循环体
(可以在此加入更新表达式)
}
布尔表达式true则运行循环体,false则终止循环。
循环次数:0~n次
do…while循环:
语法:
do{
循环体
(可在此加入更新表达式)
}(while);
它时先执行再判断,执行次数是1~n次
class Method3
{
public static void main(String[] arg)
{
java.util.Scanner s = new java.util.Scanner(System.in);
System.out.println("请输入一个整数:");
int n = s.nextInt();
System.out.println(circulation(n));
//以上代码等同于:int n = circulation(n);System.out.println(n);
}
public static int circulation(int n)
{
while(true)
{
n++;
if(decide(n))//判断decide(n)的返回值是true or false,正确则继续运行,运行到break则表示n为素数。然后程序终止
{
break;
}
}
return n;//如果n为素数则为main函数返回m的值。
}
public static boolean decide(int a)
{
boolean x = true;
for(int i = 2; i < a; i++)
{
if (a%i == 0)//如果a取i的余数为0则表示这个数不为余数,判断错误。
{
x = false;
}
}
//程序运行到这一步表示该数为素数。
return x;//返回boolean x的值,true或false。
}
}
break翻译成折断,弄断。
用在两个位置(其他位置不行):
第一个位置:switch语句当中,用来终止switch语句的执行。防止case穿透
第二个位置:用在循环语句(for;while;do..while)中,用来终止循环执行(遵循就近原则,终止离它最近的循环)。
用break语句终止指定的循环:
第一步:需要先给循环起名:
a : for(){
b : for(){
}
}
第二步:终止 : break a;
作用:终止当前本次循环。
注意与break的区别:break是终止循环。
作用:用来终止离他最近的方法。
意义:方法是一段可以完成某个特定功能的并且可以被重复利用的代码片段。方法的出现,让代码有了很强的复用性。
方法的语法机制:
[修饰符列表] 返回值类型 方法名(形式参数列表){
方法体;
}
返回值类型:
返回值是一个方法执行结束之后的结果。
注意:
1,中括号内的内容[修饰符列表]表示不是必须的,可选择的。
2,返回值可以是8种基本数据类型和引用数据类型
3,返回值void意思是方法执行结束后不返回任何结果。
4,如果返回值不是void,那就必须在程序结束后加上return;
5,只要有”return“关键字的语句执行,那当前所在的方法结束(不是程序结束!)。
6,除了void之外,其它类型都必须得是:return 值;(void,可以用return,后面不能加值!!!)
形式参数列表:
简称:形参
注意:
形式参数列表中的每一个参数都是”局部变量“,方法结束之后内存释放。
形参个数是:0~N个。多个形参用 英文逗号,隔开。
形参的数据类型起决定性作用,形参对应的变量名可随意更改。
方法调用:
语法:类名.方法名(实际参数列表)
实际参数列表,简称:实参。
实参与形参的类型,个数,必须一一对应。
调用同一个类的方法时”类名.“可以省略,跨类调用时不能省略。
一种经典的数据结构。
栈数据结构:stack–存储每个方式执行时所需要的内存空间(局部变量)
1,什么是数据结构:
数据结构通常是:存储数据结构的容器。而该容器可能存在不同的结构。
常见的数据结构:数组,链表,图,二叉树,栈,队列。
栈数据结构的特点:== 先进后出,后进先出。==
注意!!!处于栈顶部的元素具备活跃权。
名词:
栈顶元素,栈帧(永远指向栈顶元素),栈底元素。
进栈,入栈,压栈,push,
出栈,弹栈,pop。
在同一个类种,如果”功能1“与”功能2“它们的功能是相似的,那么可以考虑将它们的方法名一致,这就叫方法重载。
注意:
方法重载overload不能随便使用,如果两个功能压根不相干,不相似,根本没关系,此时两个方法使用重载机制的话,会导致编码更麻烦,无法进行方法功能区分。
什么时候代码会发生方法重载?
条件1:在同一个类当中。
条件2:方法名相同
条件3:参数列表不同。(个数,类型,顺序不同!)
只要同时满足以上3个条件,那么我们可以认定方法和方法之间发生了重载机制。
意思:方法自己调用自己,这就是方法递归。
注意:
递归没有结束条件的时候或压栈太深,内存不够,都会发生内存溢出错误。即栈溢出错误。
所以:递归必须要有结束条件。
建议:
在实际开发中,不建议轻易选择递归
尽量使用循环语句代替,循环效率高,耗费内存少。
递归耗费的内存较大,使用不当会导致JVM死机。
(但是在极少数情况下,不用递归,这个程序没法实现。)
假如在实际开发中,假设有一天你真正的遇到了StackOverflowError,如何解决问题?
第一步:先检查递归的结束条件,如果递归结束条件不对,必须对条件进一步修改,直到正确为止。
第二步:假设递归条件没问题,怎么办?
这时候需要手动调整JVM的栈内存初始化大小。可以将栈内存空间调大。
打开控制台,输入java -x ; java -Xss xxxGB(不能超出你电脑实际内存。)
java -x 可以查看调整栈大小的参数。
注意步骤,注重的是实现这个功能的步骤。
第一步干什么
第二步干什么
.......
面向过程也注重实现功能的因果关系。
因为A所以B
因为B所以C
因为C所以D
........
面向过程中没有对象的概念,知识实现这个功能的步骤以及因果关系。
面向过程最主要的是每一步与每一步的因果关系,其中A步骤因果关系到B步骤,A和B联合起来形成一个子模版,
子模版与子模版之间又因为因果关系结合在一起。
如果其中一个因果关系出了问题,此时整个系统的运转都会出现问题。
(代码和代码之间的耦合度太高,扩展力太差)
对于小型项目(功能),采用面向过程的方式进行开发,效率较高。
不需要前期进行对象的提取,模型的建立,采用面向过程方式可以直接开始干活。
一上来直接写代码,编写因果关系,从而实现功能。
属性 = 成员变量 = field = 域 ,字段
方法 = 成员方法 = 函数 = method
创建类的对象 = 类的实例化 = 实例化类
采用面向对象的方式进行开发,更符合人类的思维方式。
面向对象就是将现实世界分割成不同单元,每一个单元都实现成对象,然后驱动一下,让各个对象之间协作起来。
耦合度低,扩展力强。
案例:
蛋炒饭:鸡蛋和米饭完全混合在一起,没有独立对象概念。
假如客户只想吃米饭,怎么办?
客户提出需求,软件开发者必须满足这个需求,于是开始扩展,(很难扩展,耦合度太高)
盖饭:
鱼香肉丝盖饭:鱼香肉丝是一道菜,可以看成独立对象,米饭可以看成独立对象。
假如客户提出新需求,则只需要将其中一个或多个对象换掉即可。
面向过程主要关注的是:实现步骤以及整个过程。
面向对象主要关注的是:对象A,对象B,对象C,或者对象ABC组合,对象CBA组合。
当我们采用面向对象的方式贯穿整个系统时,涉及三个术语:
整个软件开发过程,都是采用OO进行贯穿。
实现程序的步骤:
OOA----OOD----OOP
面向对象中最主要的是”对象“;
类 = 属性+方法;
属性描述的是:状态;
方法描述的是:行为动作;(一个方法代表了一个动作)
在现实当中是不存在的,是一个抽象的该你那,是一个模板。是我们人类大脑进行思考,总结,抽象的一个结果。(类是对象特征的总结)
举例:明星----是一个类。
举例:宋小宝,刘德华,周星驰就是对象。属于”明星“类。
抽象:多个对象具有共同特征,进行思考总结抽取共同特征的过程。
实例化:通过类这个模板创建对象的过程,叫做:实例化。
类----【实例化】----对象
对象----【抽象】----类
在Java中要想得到”对象“,必须先定义”类“,对象属于类。这个模板是创造出来的。
类就是一个模板:类中描述的是所有对象的”共同特征信息“。对象就是通过类创建出来的个体。
语法格式:
[修饰符列表] class 类名{
类体 = 属性 + 方法
属性在代码上以变量的形式存在(描述状态)
方法描述动作/行为
}
当一个类没有提供任意一个构造方法,系统会默认提供一个无参构造方法。
这个无参构造方法叫做:缺省构造器。
但是如果定义了一个有参数的构造方法,就不会再提供方法。
建议:将无参数构造方法手动写出来,这样编译时一定不会出现问题。
作用:创建对象,并且创建对象的过程中给属性赋值(初始化。)
语法格式:
[修饰符列表] 构造方法名(形式参数列表){
构造方法体;
}
注意:
第一:修饰符列表目前统一写:public。千万不要写public static。
第二:构造方法名和类名必须一致。
第三:构造方法不需要返回值类型,也不能写void,写上void表示普通方法,而不是构造方法。
调用构造方法:
使用new运算符来调用构造方法。
语法格式:
new 构造方法名(实际参数列表);
public class Adress
{
String street;
String home;
String home2;
//无参构造方法
public Adress(){
}
//有参构造方法:创建对象,并给对象赋初始值。
public Adress(String a2, String a3, String a4){
street = a2;
home = a3;
home2 = a4;
}
}
public class Student
{
//属性(描述状态),以成员变量的状态存在
int numble;
String name;
int age;
boolean sex;
Adress adr;
//无参构造方法
public Student(){
}
//有参构造方法:
public Student(int num, String na, int ag){
//给实例化变量赋值,(初始化实例变量,初始化属性)
numble = num;
name = na;
age = ag;
}
public Student(int num, String na, int ag, boolean se){
numble = num;
name = na;
age = ag;
sex = se;
}
public Student(int num, String na, int ag, boolean se,Adress ad){
numble = num;
name = na;
age = ag;
sex = se;
adr = ad;
}
}
public class StudentTest
{
public static void main(String[] arg){
Adress a = new Adress("湖北","武汉","汉阳区");
//调用不同的构造方法创建对象。
//创建学生对象1
Student s1 = new Student();
System.out.println(s1.numble);
System.out.println(s1.name);
System.out.println(s1.age);
System.out.println(s1.sex);
//s1.adr.home可以拆分为:
//Adress ss = s1.adr;
//String hm = ss.home;
//System.out.println(ad);
//System.out.println(s1.adr.home);
//创建学生对象2
Student s2 = new Student(1000, "李某", 10);
System.out.println(s2.numble);
System.out.println(s2.name);
System.out.println(s2.age);
System.out.println(s2.sex);
//System.out.println(s1.adr.home);
//创建学生对象3
Student s3 = new Student(2000, "tete", 15, true);
System.out.println(s3.numble);
System.out.println(s3.name);
System.out.println(s3.age);
System.out.println(s3.sex);
//System.out.println(s1.adr.home);
//创建学生对象4
Student s4 = new Student(2000, "tete", 15, true);
s4.adr = a;
System.out.println(s4.numble);
System.out.println(s4.name);
System.out.println(s4.age);
System.out.println(s4.sex);
System.out.println(s4.adr.street+s4.adr.home+s4.adr.home2);
}
}
面向对象三大特征:
== 封装;继承;多态; ==
有了封装才有继承,有了继承才有多态。
将内部用一个坚硬的壳保护起来。保证内部的东西是安全的。
让使用者只需要通过几个按钮就可以完成操作。
作用:
一个类体当中的数据,假设封装之后,对于代码的调用人员来说,不需要关心代码的复杂实现,只需要通过一个简单的入口就可以访问了。
另外,类体中安全级别较高的数据封装起来,外部人员不能随意访问,保证数据的安全性。
get方法要求:
public 返回值类型 get+属性名首字母大写(无参){
return ***;
}
set方法的要求:
public void set+属性名首字母大写(有1个参数){
*** = 参数;
}
代码:
public class Person
{
//private 表示私有的,被这个关键词修饰之后,该数据只能在本类中访问。
//出了这个类,age属性就无法访问了,私有的。
//age是成员变量,在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;
}
}
public class PersonTest
{
public static void main(String[] args){
//创建对象
Person ag = new Person();
//这里是读取age年龄
//读取调用getAge()方法:
//int aa = ag.getAge;
//System.out.println(ag.getAge());
//11行代码等同于8,9行代码的结合
System.out.println(ag.getAge());
//因为setAge没有返回值,不需要变量去接收。
ag.setAge(10);
System.out.println(ag.getAge());
ag.setAge(-20);
System.out.println(ag.getAge());
}
}
带static 和不带static :
方法中带static,main方法就使用“类名.”的方式访问
方法中不带static(称为:实例方法),main方法需要先new 一个对象,再通过“引用.“的方式去访问
实例都是对象相关的,访问时采用”引用.“的方式访问。需要先new对象。
实例相关的,必须现有对象,才能访问,可能会出现空指针异常。
静态的都是类相关的,访问是采用”类名.“的方式访问,不需要new对象
静态变量在类加载时初始化,不需要new对象,静态变量的空间就开出来了,存储在方法区。
如果这个类型的所有对象的某个属性值都是一样的,不建议定义为实例变量,浪费内存空间。建议定义为类级别特征,定义为静态变量,在方法去只保留一份,节省内存开销。
一个对象一份的是实例变量,所有对象都有一份是静态变量。
当这个方法体中,直接访问了实例变量,那么这个方法一定是实例方法
静态访问:建议使用”类名.“来访问,但使用”引用.“也行(不建议)
静态——空指针异常
只有在”空引用“访问”实例“相关的,都会出现空指针异常。
在代码正确编译的情况下,静态不会出现空指针异常
class StaticTest
{
public static void main(String[] arg){
//通过“类名.”的方式去访问静态变量;
System.out.println(Chinese.country);
//创建对象
Chinese card = new Chinese("123123123","张三");
System.out.println(card.idCard);
System.out.println(card.name);
System.out.println(card.country);//建议使用“类名.”
//card是空引用
card = null;
//这个地方不会出现空指针异常,因为静态变量不需要对象的存在。
System.out.println(card.country);
}
}
class Chinese
{
//实例变量
String idCard;
String name;
//静态变量
static String country = "中国";
//构造方法
public Chinese(){
}
public Chinese(String x, String y){
idCard = x;
name = y;
}
}
假如静态方法中访问实例变量,必须先在静态方法中new 一个对象,再用“引用.”去访问。
实例方法中访问静态变量,采用“类名.”;
语法:
static {
java语句;
java语句;
}
static静态代码块在什么时候执行呢?
类加载时执行,并只执行一次。
静态代码块特征/特点:
静态代码块在类加载器时执行,并且在main方法执行之前。
静态代码块一般是按照自上而下的顺序执行。
一个类中可以写多个静态代码块。
代码:
class StaticTest05
{
//静态代码块
static{
System.out.println("A");
}
//一个类当中可以编写多个静态代码块
static{
System.out.println("B");
}
//入口
public static void main(String[] arg){
System.out.println("Hallo,World!!");
}
//编写一个静态代码块
static{
System.out.println("c");
}
}
语法:
{
java语句;
java语句;
java语句;
}
实例语句块在类加载时并没有执行。
只要是构造方法执行,必然在构造方法执行之前,自动执行”实例语句块“中的代码。
代码:
class InstanceCode
{
public static void main(String[] arg)
{
System.out.println("main begin");
new InstanceCode();
}
//实例语句块,实例块语句存放在堆内存中。
{
System.out.println("实例语句块执行!");
}
//Constructor无参构造方法
public InstanceCode()
{
System.out.println("无参构造方法!");
}
//有参构造方法
public InstanceCode(String name)
{
System.out.println("有参数的构造方法");
}
}
判断运行顺序:
//执行顺序。
class CodeOrder
{
static{
System.out.println("A");
}
public static void main(String[] arg){
System.out.println("B");
new CodeOrder();
System.out.println("F");
}
{
System.out.println("C");
}
public CodeOrder(){
System.out.println("D");
}
static{
System.out.println("E");
}
}
在实例方法与构造方法中,为了增强代码可读性,会出现同样命名,
为了区分局部变量和实例变量,这种情况下:"this."是不可省略的。
this 出了可以使用在实例方法中,还可以用在构造方法中。
新语法:
通过当前的构造方法去调用另一个本类的构造方法,
可以使用以下语法格式:
this(实际参数列表);
this(***,***,***);
作用是:
通过构造方法1去调用构造方法2,可以做到代码复用。
//银行存取钱
class Bank
{
public static void main(String[] arg){
Account baby = new Account("Jane Smith", 1000L, 2000.0, 1.25);
Customer baby2 = new Customer("陈某",baby);
//把Account类的地址赋给baby2,第一个getId是baby2中的Id,第二个getId是baby中的Id
System.out.println(baby2.getName()+ baby2.getId().getId());
baby.deposit(100.0);
baby.giao();
baby.withdraw(960);
baby.withdraw(2000);
baby.giao();
}
}
//声明一个顾客类
class Customer
{
private String name;
private Account id;
//构造无参方法
public Customer()
{
}
//定义有参数构造器
public Customer(String name,Account id)
{
this.name = name;
this.id = id;
}
//set,get方法
//Name名字
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
//Id 银行卡号
public Account getId()
{
return id;
}
public void getId(Account id)
{
this.id = id;
}
public void giao2(){
}
}
//声明一个账户类
class Account
{
private String name;
private long id;
private double balance;
private double annualInterestRate;
public Account()
{
//无参构造方法调用有参构造方法1。
//这里this();不能省略。
this("陈某",1111L,50000,1.56);
}
public Account(String name,long id,double balance, double annualInterestRate)
{
this.name = name;
this.id = id;
this.balance = balance;
this.annualInterestRate = annualInterestRate;
}
//get.set名字
public String getName()
{
return name;
}
public void setName(String name){
//this.的作用:区分局部变量和实例变量,这里不能省略,
//因为String name 省略编译器会分不清谁是局部变量,谁是实例变量
//this.name 表示实例对象
//增强可读性
this.name = name;
}
//get.set账户ID
public long getId()
{
return id;
}
public void setId(long id){
this.id = id;
}
//get.set余额
public double getBalance()
{
return balance;
}
public void setBalance(double balance){
if(this.balance < 0)
{
System.out.println("余额不足,取钱失败");
return;
}
this.balance = balance;
}
//get.set年利率
public double getAnnualInterestRate()
{
return annualInterestRate;
}
public void setAnnualInterestRate(double annualInterestRate){
this.annualInterestRate = annualInterestRate;
}
//取款方法:
public double withdraw(double with)
{
if(balance < with)
{
System.out.println("余额不足,取钱失败。您的余额还有:" + balance);
return balance;
}else
{
//else里面的代码等同于:this.setBlance(this.getBalance() - with)
balance -= with;
System.out.println("您的余额还有:" + balance);
return balance;
}
}
//存款方法:
public double deposit(double dep)
{
//this.setBalance(this.getBalance() + with);
balance += dep;
System.out.println("成功存入" + dep +"元,余额还剩:"+balance+"元");
return balance;
}
public void giao()
{
//this.默认隐藏的。
System.out.println("贵宾姓名:" + this.name);
System.out.println("贵宾银行ID:" + this.id);
System.out.println("贵宾余额:" + this.balance);
System.out.println("银行年利率:" + annualInterestRate +"\n");
}
}
基本作用:子类继承父类,代码可以得到复用。
主要作用:因为有了继承关系,才有了后期方法覆盖和多态机制。
继承的相关特性:
满足什么条件的时候可以使用继承extends?
凡是采用“is a”能描述的,都可以继承
例如:Cat is a Animal:猫是一只动物。
代码:
class Extends
{
public static void main(String[] arg){
Cat c = new Cat();
c.name = "笑话";
c.move();
}
}
class Animal
{
//名字:
String name;
//提供一个动物移动方法
public void move(){
System.out.println(name + "正在移动!");
}
}
//Cat继承Animal类,Cat 是子类
class Cat extends Animal
{
}
什么时候进行方法覆盖:
子类继承父类之后,当继承过来的方法无法满足当前子类的业务需求时,子类有权对这个方法进行重新编写,有必要进行“方法覆盖”
方法覆盖又叫做:方法重写,英文单词叫做:Override,Overwrite都可以。
方法覆盖条件:
注意:
存在的作用就是将jva对象转换成字符串形式,大多数的java类toString()方法都是需要覆盖的。因为Object类中提供的toString()方法输出的是一个java对象的内存地址。
格式可以自己定义,或者听取项目要求。
代码:
//方法覆盖经典例子
class OverrideTest
{
public static void main(String[] args)
{
//创建一个中国人对象c
//暂时无法在()内填写属性,因为该类中暂时没有构造方法。
ChinaPeople c = new ChinaPeople();
//创建一个美国人对象a
AmericanPeople a = new AmericanPeople();
c.setName("李某");
c.speak();
a.setName("李某");
a.speak();
}
}
//人
class People
{
//属性
private String name;
//无参构造方法
public People()
{
}
//有参构造方法
public People(String name)
{
this.name = name;
}
//set改写
public void setName(String name)
{
this.name =name;
}
//get读取
public String getName()
{
return name;
}
//动作speak方法.
public void speak()
{
System.out.println(name + "正在。。。");
}
}
//"中国人" 类 继承了"人" 类 ,等同于将People类中的方法复制了一份在ChinaPeople中。
class ChinaPeople extends People
{
public void speak(){
//由于继承关系,这里的this.是表明这个People类中的当前对象。可省略
System.out.println(this.getName() + "正在说汉语。");
}
}
//"美国人" 类 继承了"人" 类 ,等同于将People类中的方法复制了一份在American中。
class AmericanPeople extends People
{
public void speak()
{
//由于继承关系,这里的this.是表明这个People类中的当前对象。可省略
System.out.println(this.getName() + "正在说英语.");
}
}
1,普及两个概念:
第一个:向上转型:子——>父(自动类型转换)(upcasting)
第二个:向下转型:父——>子(强制类型转换,需要加强制类型转换符)(downcasting)
当你需要访问的是子类中特有的方法,则需要向下转型,需要加强制类型转换符。
注意:
Java中允许向上转型,也允许向下转型,无论向下转型,还是向上转型,必须要有继承关系!!!
在向下转型时,一定要写。
第一:instanceof可以在运行阶段动态判断引用指向的对象的类型。
第二:instanceof语法:(引用 instanceof 类型)
第三:instanceof运算符的运算结果只能是true/false
第四:c是一个引用,c变量保存了内存地址指向了堆中的对象
假设(c instanceof Cat)为true:
c引用指向的堆内存中的Java对象是一个Cat
假设(c instanceof Cat)为false:
c引用指向的堆内存中的Java对象不是一个Cat
降低程序的耦合度,提高程序的扩展力。(几乎天天使用)
多种形态,多种状态,编译和运行有两个不同的状态
编译期叫做静态绑定;
运行期叫做动态绑定;
Animal a = new Cat();
//编译的时候编译器发现a类型是Animal,
所以编译器会去Animal类中找move()方法,
找到后,绑定,编译通过。
但是运行的时候和底层堆内存中的实际对象有关,
真正执行的时候会自动调用“堆内存中真实对象”相关方法。
a.move();
多态典型代码:父类型的引用指向子类型的对象。(Java中允许这样写代码)
public class Master{
public void feed(Dog d){}
public void feed(Cat c){}
}
以上代码中表示:Master和Dog以及Cat的关系很紧密(耦合度高)。导致扩展力差。
public class Master{
public void feed(Pet pet){}
}
以上代码中表示:Master和Dog以及Cat的关系就脱离了,Master关注的是Pet类。
这样Master和Dog以及Cat的耦合度就降低了,提高了软件的扩展性。
代码:
public class Homework
{
public static void main(String[] arg)
{
//第一种写法:
Erhu e = new Erhu();
Piano p = new Piano();
Violin v = new Violin();
Musician m = new Musician();
m.play(e);
m.play(p);
m.play(v);
//第二种写法:
/*
Instrument e = new Erhu();
Instrument p = new Piano();
Instrument v = new Violin();
Musician m = new Musician();
m.play(e);
m.play(p);
m.play(v);
*/
//第三种写法:
/*
Musician m = new Musician();
m.play(new Erhu());
m.play(new Piano());
m.play(new Violin());
*/
}
}
//乐器父类
class Instrument
{
public void makeSound()
{
System.out.println("乐器的声音!");
}
}
//子类
class Erhu extends Instrument
{
//方法重写
public void makeSound()
{
System.out.println("二胡的声音!");
}
}
class Piano extends Instrument
{
public void makeSound()
{
System.out.println("钢琴的声音!");
}
}
class Violin extends Instrument
{
public void makeSound()
{
System.out.println("小提琴的声音!");
}
}
//乐手类
class Musician
{
/*
第一种写法:
Instrument i;
public Musician(){}
public Musicain(Instrument i)
{
this i = i;
}
public void play(Instrument i)
{
i.makeSound();
}
*/
//第二种写法:
//把m.play()括号中的变量传给i,
//编译器会去Instrument类中去查找makeSound方法,
//然后调出子类方法重写后的makeSound
public void play(Instrument i)
{
i.makeSound();
}
}
问题:静态方法存在方法覆盖吗?
方法覆盖与方法相互联系,多态必须有对象。
多态自然就和对象有关系了。
而静态方法的执行不需要对象
所以,一般情况下,我们会说静态方法“不存在”方法覆盖。
不探讨静态方法覆盖。
问题:私有方法不能覆盖。
问题:在方法覆盖中,方法的返回值类型?
对于返回值类型是基本数据类型来说,必须一致。
对于引用数据类型,大转小可以,小转大不行(意义不大,实际开发一般不会用到。)
问题:什么条件满足后,会构成方法覆盖呢?
发生具有继承关系的两个类之间。
父类中的方法和子类重写之后的方法。
具有相同的方法名,相同的形式参数列表,相同的返回值类型。
super是一个关键字,全部小写。
"super."和"this."可以访问方法和属性。
super.属性名;【访问父类的属性】
super.方法名(实参);【访问父类的方法】
super(实参);【调用父类的构造方法】
表示通过子类的构造方法调用父类的构造方法。
模拟现实世界中的这种场景:要想有儿子,需要先有父亲。
super(实参)的作用:初始化当前对象的父类型特征,并不是创建新对象。实际对象只创建了一个对象
当一个构造方法第一行:即没有thi()又没有super()的话,默认会有一个super();
表示通过当前子类的构造方法调用父类的无参数构造方法。
如果super()括号中有变量,则会调用父类的有参构造类型。
所以必须保证父类的无参数构造方法是存在的。
this()与super()不能共存,它们都只能出现在构造方法的第一行。
super不是引用。super也不保存内存地址,super也不指向任何对象。
super只是代表当前对象内部的那一块父类型的特征。
super.什么时候不能省略?
区分子类和父类的同名属性:
this.name:当前对象的name属性
super.name:当前对象的父类型特征中的name属性。
如果父类和子类有同名属性,并且想要通过子类访问父类属性,则不能省略。
代码:
public class superTest03
{
public static void main(String[] arg)
{
Vip p = new Vip("张三");
p.shopping();
}
}
class Customer
{
String name;
public Customer(){
}
public Customer(String name)
{
this.name = name;
}
}
class Vip extends Customer
{
//假设子类也有一个同名属性,java中允许在子类中出现和父类同名的变量。
String name;
public Vip(){}
public Vip(String name)
{
super(name);
//this.name = null; 这是省略,默认给name赋值null。
}
public void shopping()
{
//this表示当前对象
System.out.println(this.name+"正在购物");
//super表示的是当前对象的父类型特征。(super是this指向的那个对象中的一块空间)
System.out.println(super.name+"正在购物");
//name前面省略了this.
System.out.println(name+"正在购物");
}
}