关键字:
一般是编译器(eclipse或者idea)高亮显示的都是java当中的关键字,这些关键字是程序员开发者不能修改的东西,比如public class static package等等,是sun公司规定好的。
标识符:
是程序员开发者能自己命名的单词,比如类名、方法名、变量名这些都是标识符
其中 Hello、main就是标识符
public class Hello {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
标识符在使用的时候要遵守规则和规范:
a、规则:字母、数字、下划线、美元符号($),不能以数字开头,不能使用关键字
规则就是法律、语法,必须遵守,不遵守java语言就不通过,编译不通过
b、规范:可以不遵守,但我建议大家跟规则一样都要遵守,不遵守java也不会报错,跟道德一样
1.1 见名知意
1.2 驼峰式命名,有高有低,高低指的是英文的大小写
类名:首先不能用中文,用英文每个单词首字母大写,比如UserLogin
方法名:首字母小写,其余大写,比如eatFoods
变量名:
常量:每个单词全大写,单词之间下划线分开,COMPUTER_COLOR就是常量
public static final String COMPUTER_COLOR = "红色";
普通变量:首字母小写,其余大写,比如 computorBrand
字面值:java当中的数据,java语言组成部分,跟关键字、标识符一样
10、100、-200 整数
1.2 -1.2 浮点数
true、false 布尔值
'A' 'b' '我' 字符
“LiMing” 字符串
计算机的一些常识
byte kb mb gb tb
1kb = 1024b
1mb = 1024kb
1gb = 1024mb
1tb = 1024gb
现在的计算机都是交流电的形式运行的,他只识别所谓的0、1电信号
java当中的8种数据类型:
整数型:
byte
short
int
long
浮点型(一般用来表示小数的):
float
double
字符型
char
布尔型
booblean
进制:
2进制 0001
10进制 1 2 3 11 12 13
8进制 012
16进制 0xF
数据类型 占用字节数(1字节=8bit 也就是8位)
--------------------------------------------
byte 1
short 2
int 4
long 8
float 4
double 8
boolean 1
char 2
注意:
1、在java当中定义的整数字面值默认是int类型
在我们平常使用的时候,不要太过纠结它的大小,一般用默认的int类型定义整数就可以了。
2、类型转换问题:
用小范围的数接收大范围的数的时候,需要进行强制类型转换,但是转换之后的数据会不准确,也就是精度丢失。
强制类型转换的时候慎重加慎重。
只要涉及到类型转换就要慎重!!!!!
3、在java当中定义浮点字面值的时候默认是double类型
4、默认值:一切向0看齐
整数:默认值就是0
浮点数:默认0.0
布尔值:默认false
编码:计算机协会规定了一套标准,用来作为计算机和文字之间的一套字典参照表,文字和数字之间的转换表,
因为计算只认0、1,单纯的文字计算机解释不了。
解码:计算机按照规定格式的字典参照(编码格式),将存储到计算机内存当中的编码后的二进制文字再解释出来。
编码-解码要按照同一套标准,如果两边标准不一致,就会出现乱码的问题。
常见的编码格式:Ascll、GBK、Unicode(Utf-8)
以后开发当中经常用到的编码UTF-8
如何定义一个字符:
语法: char 变量名 = 字面值;
字面值是用''括起来的字符,字符只能是单个字符,当然转义字符是一种特殊的字符,不要混淆了,其实也是单 个字符。
如: char char1 = 'A';
char cahr2 = '我';
char char3 = '\u0001';
转义字符:有一些特殊的字符无法用我们认识的文字表示出来,就规定了可以将常见的字符进行转义,表示出来
比如
\n, 不加\ 就是一个普通的n字符,加了就是回车或换行
\t, 不加\ 就是一个普通的t字符,加了就是tab键
\\ \b \r
加(+)、减(-)、乘(*)、除(取商/ 取余%)、自增(++)、自减(–)
注意:核心点自增和自减
自增: ++前后都可以放变量
变量在前:先用后本身的值加1
变量在后:先本身的值加1再用
自减: --前后都可以放变量
变量在前:先用后变量本身的值减1
变量在后:先本身的值减1再用
public class Test03 {
public static void main(String[] args) {
int a = 10;
int b = 3;
System.out.println(a+b);
System.out.println(a-b);
System.out.println(a*b);
System.out.println(a/b);
System.out.println(a%b);
//++ --
//a++ 先用后加
//++a 先加后用
System.out.println("===========");
int c = 1;
System.out.println(c++);//1
System.out.println(++c);//3
System.out.println(c++);//3
System.out.println(++c);//5
System.out.println("############");
int d = 1;
int f = d++;
//在程序跑完第23行的时候,它做了哪些事情
//做了两件事
//第一件事情:先把d的值给f
//第二件事情:d自增,就是d本身加1,这时候d=d+1变成了2
//注意前后两件事是按顺序的
//f=1;
//d=2;
System.out.println(d);
System.out.println(f);
f = ++d;
//在程序跑完第35行的时候,它做了哪些事情
//做了两件事
//第一件事情:d自增,就是d本身加1,这时候d=d+1变成了3
//第二件事情:把自增后的d的值给到了f
//注意前后两件事是按顺序的
//d=3
//f=3
System.out.println(d);
System.out.println(f);
}
}
= (赋值)
+=(加等于)
-= (减等于)
*=(乘等于)
/= (除等于)
%=(模等于)
注意:
1、做这些运算的时候,可能会出现精度丢失,也就是数据丢失的问题,需谨慎,而且编译器是不会报错的
能解决的方法就是多自测
2、会存在类型转换的问题,不要想当然的认为a+=b就是a=a+b,具体以下为例
public class Test04 {
public static void main(String[] args) {
int a = 10;
int b = 2;
a += b;
System.out.println(a);//12
System.out.println(b);
a -= b;
System.out.println(a);//10
a *= b;
System.out.println(a);//20
a /= b;
System.out.println(a);//10
a %= b;
System.out.println(a);//0
System.out.println("============");
byte c = 126;
//byte f = 128;
int d = 2;
c += d;//c = 126+ 2
//byte c = 128;
//做这些运算的时候可能会出现精度丢失的问题
//编译器是检查不出来的,所以以后编程需谨慎,多自测
System.out.println(c);
long f = 100;
int g = 200;
f += g;
System.out.println(f);
double h = 10.1;
//g += h 并不等价于 g=g+h
//无论是+=还是-=等等赋值运算符会存在自动类型转换的问题
//其实下边这两个是等价的
g += h;
g = g + (int)h;
}
}
表达式:变量和符号组成的一条式子,它的结果是一个值;
< <= >= ==
表达式和表达式之间可以串联使用
public class Test05 {
public static void main(String[] args) {
System.out.println(4 == 3);
System.out.println(4 != 3);
System.out.println(4 > 3);
System.out.println(4 < 3);
System.out.println(4 >= 3);
System.out.println(4 <= 3);
boolean a = (4 > 3);
boolean b = (5 < 2);
System.out.println(a == b);
System.out.println((4 > 3) == (5 < 2));
}
}
什么是短路:
在程序当中正常的执行顺序被某个运算符给中断了,一条语句后边程序就不执行(不是不需要)了,
类似于生活中的短路现象。
常用的逻辑运算符:
!非
&&短路与
|| 短路或
具体后两种逻辑运算符达短路现象以下程序为例
public class Test01 {
public static void main(String[] args) {
System.out.println(!(4 > 3));
int a = 1;
//&&短路与
//true && true 为true
//true && flase 为false
//false && true 为false
//false && false 为false
System.out.println((4>3) && (5<2));//false
System.out.println((4<2) && (5>a++));
System.out.println(a);
//||短路或
//true || true 为true
//true || flase 为true
//false || true 为true
//false || false 为false
System.out.println((1>3) || (4<5));
int b = 2;
System.out.println((5>3) || (6<b++));
System.out.println(b);
}
}
语法:
条件表达式 ? 表达式1 : 表达式2;
注意:
1、三元运算结果是一个值,不能作为一条独立的语句;
2、后边两个表达式的数据类型要统一,不然编译期出错,当然发生自动类型转换的时候没问题的。
public class Test02 {
public static void main(String[] args) {
int a = 30;
int b = 30;
a = (b == 20 ? 2000 : 3000);
System.out.println(a);
//a = (b == 20 ? 2000 : 11.2);
//编译器a的类型模糊,不确定是整型还是浮点型,报错
}
}
没有必要去刻意记忆运算符的优先级,最简单的方式就是表达式之间加();
三种用法
1、if(布尔表达式){
语句体;
}
2、if(布尔表达式1){
语句体1;
}else{
语句体2;
}
3、if(布尔表达式1){
语句体1;
}else if(布尔表达式2){
语句体2;
}else if(布尔表达式3){
语句体3;
}…esle{
语句体…;
}
注意:
1、if else else if可以相互结合或者嵌套使用
2、在第三种方式里面else if是除了if或者elseif的其他情况,有些条件不要写重了
3、花括号括起来的是代码块,}不需要以分号结尾,他是一个整体结构,
只有一条条语句才需要分号结尾
public class Test03 {
public static void main(String[] args) {
int x = 0;
//if的第一种用法
if(x != 1) {
System.out.println(x);
}
int score = 60;
if(score > 90) {
System.out.println("优秀");
}
if(score < 90 && score > 70) {
System.out.println("良好");
}
if(score < 70) {
System.out.println("不及格");
}
//if的第二种用法
int age = 20;
if(age > 18) {
System.out.println("成年人");
}else {
System.out.println("未成年");
}
if(score > 70) {
if(score < 90) {
System.out.println("良好");
}else {
System.out.println("优秀");
}
}else {
System.out.println("不及格");
}
//if 的第三种用法
if(score > 90) {
System.out.println("优秀");
}else if(score > 70) {
System.out.println("良好");
}else {
System.out.println("不及格");
}
System.out.println("==========");
int score1 = 96;
if(score1 > 90) {
System.out.println("优秀");
}else if (score1 > 95) {
System.out.println("非常优秀");
}
}
}
switch开关的意思
语法:
switch(表达式){
case 常量值:
语句体;
break;//可加可不加,但是要慎重
case 常量值:
语句体;
break;
…
default:
语句体;
break;
}
注意:switch开关在用的时候,只需要知道什么时候打开什么时候结束;
当switch表达式与case常量值匹配的时候开关打开,依次执行语句,去寻找break,直到遇到break
switch结束,找不到的话,直到switch结尾;
break:一般是用来结束switch和循环的;
public class Test04 {
public static void main(String[] args) {
int weekNum = 2;
switch(weekNum) {
case 1:
System.out.println("星期一");
break;
case 2:
System.out.println("星期二");
// break;
case 3:
System.out.println("星期三");
break;
case 4:
System.out.println("星期四");
break;
case 5:
System.out.println("星期五");
break;
case 6:
System.out.println("星期六");
break;
case 7:
System.out.println("星期天");
break;
default:
System.out.println("不存在的星期数字!");
break;
}
}
}
获取键盘输入
import java.util.Scanner
public class Test05 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入一个数字:");
int a = scanner.nextInt();
System.out.println(a);
}
}
关于导包,比如
import java.util.Scanner
Scanner是别人写好的类,我们可以直接拿来用,但是,前提条件:
1、项目当中有相关的jar包
2、要通过import导入,其中上边java util都是文件夹 Scanner是类
要注意:不同文件夹下可能有同名的类,不要导错了
java.util.Scanner
这个整体叫全限定类名
注意:写循环一定不要写死循环,比如for(; while(true){} do{}while(true)
语法结构:
for(1、初始条件表达式;2、是否循环判断表达式;4、增量表达式(步幅)){
3、循环执行的程序(循环体);
}
它的执行顺序:
第一步:初始表达式(只执行一次)
第二步:是否循环
如果第二步为真,执行第三步
如果第二步为假,结束
第三步:执行循环体,执行第四步
第四步:变量进行增量操作,执行第二步
public static void main(String[] args) {
//int x=1只执行一遍
for(int x = 1; x <= 100; x++) {
System.out.println(x);
}
}
注意:1、2、4三个表达式可以不写,但是成死循环了
for循环内初始表达式定义的变量只能在for循环里面使用,如果想在for循环外边使用该变量,需要把这个变量定义在for循环外边
public static void main(String[] args) {
//int x=1只执行一遍
int x;
for(x = 1; x <= 100; x++) {
System.out.println(x);
}
System.out.println(x);
}
增量表达式位置比较灵活,也可以写在循环体里面
语法: while(循环条件表达式){
循环语句;
}
/*
* 输出1-100内3的倍数
* */
public class Test03 {
public static void main(String[] args) {
int x = 1;
while(x <= 100) {
if(x % 3 == 0) {
System.out.println(x);
}
x++;
}
}
}
语法: do{
循环语句;
}while(循环条件表达式);
/*
* 打印1-100之内的偶数
* */
public class Test04 {
public static void main(String[] args) {
int x = 1;
do {
if(x % 2 == 0) {
System.out.println(x);
}
x++;
}while(x <= 100);
System.out.println("========");
System.out.println("++++++++++");
}
}
注意:while循环是先判断后执行循环语句
dowhile先执行循环语句再判断
break:
1、意为中断终止的意思
2、break;是一条独立的语句
3、可以用在switch中,可以用在循环当中
用在switch中是用来关闭开关的
用在循环当中用来结束当前for循环,离它最近的循环,结束不意味着整个程序终止,终止的是一个代码 块,代码块这里就是所谓的循环体
/*
* 输出256-1688内两个13的倍数
* */
public class Test05 {
public static void main(String[] args) {
int sum = 0;
int x;
for(x = 256; x <= 1688; x++) {
if(x % 13 == 0) {
System.out.println(x);
sum = sum + 1;
if(sum == 2) {
break;
}
}
}
System.out.println(x);
}
}
continue:
继续的意思,用于跳出当前循环(离它最近的循环),继续下一次循环;
continue;是一条独立的语句
/*
* 打印1-100内非7的倍数的整数
* */
public class Test06 {
public static void main(String[] args) {
for(int x = 1; x <= 100; x++) {
if(x % 7 == 0) {
continue;
}
System.out.println(x);
}
}
}
定义:用来存储多个相同数据类型的数据模型(相同、多个)
声明方式:
第一种: 数据类型[] 数组变量名 = {};
{}里面是具体存放的一个对应数据类型的数
例:int[] twoDepAges = {20,30,18};
第二种:数据类型[] 数组变量名 = new 数据类型[数组的长度];
以上两种方式都是要在JVM堆内存中开辟一段内存空间,用来存放数组数据,数组变量名是赋的值不是表面上看到的数组,其实是数组变量赋的值是堆内存存放数组数据所在的地址,并且这个地址数据又被放在了栈内存当中。
注意:数组每一次声明,都是要重新开辟堆内存的,即使两个数组存的数据一样,如果是声明了两个数组变量,两个数组变量是不相等的,具体参考最后一个代码实例;
具体关于JVM内存结构,看2.3
public static void main(String[] args) {
int pengAge = 32;
int wangPengAge = 18;
int dongHaoAge = 20;
//定义了一个长度是33的整数数组
//第一种方式
//int[] twoDepAges = {10,20};
//第二种方式
int[] twoDepAges = new int[33];
}
数组的存值、取值、遍历
/*
* 第一种数组声明方式(静态初始化)
* 存值
* 取值
* 遍历
* */
public class Test02 {
public static void main(String[] args) {
//声明,在声明的时候已经存值了
int[] depAges = {18,20,30};
//取值,取出第三个位置的存放的数
//数组变量名[下标]
int pengAge = depAges[2];
System.out.println(pengAge);
System.out.println(depAges[0]);
//数组越界,取值的时候下标不能超出数组的长度范围
// System.out.println(depAges[3]);
System.out.println("=============");
//数组遍历
for(int x = 0; x <= 2; x++) {
System.out.println(depAges[x]);
}
int[] depHigh = {44,3,55,23,33,45,89,42,77};
//获取数组的长度
//数组变量名.length, length不是最大的下标,其实就是
//数组数据的个数
System.out.println(depHigh.length);
for(int y = 0; y < depHigh.length; y++) {
System.out.println(depHigh[y]);
}
//增强for循环
int[] depWeight = {12,13,14};
for(int z : depWeight) {
System.out.println(z);
}
boolean[] flags = {true,false,false};
for(boolean m : flags) {
System.out.println(m);
}
}
}
/*
* 第二种数组声明方式,动态初始化
* 存值
* 取值
* 遍历:两种声明方式的遍历是一样的
* */
public class Test03 {
public static void main(String[] args) {
//这里的33是指的数组里面数据的个数,数组的长度
//其实这种方式也存值了,只不过不同数据类型系统给了一个默认值
//整型:0
//浮点型:0.0
//布尔型:false
//引用数据类型:null
int[] depAges = new int[33];
System.out.println(depAges[1]);
double[] depAges1 = new double[20];
System.out.println(depAges1[3]);
boolean[] depAges2 = new boolean[12];
System.out.println(depAges2[4]);
//重新赋值(存值)
//int a = 0;a = 30;
System.out.println(depAges[2]);
depAges[2] = 30;
System.out.println(depAges[2]);
}
}
关于数组的比较,以下为例,自己结合JVM体会一下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wtnBToBt-1662468874847)(Java学习/image-20220301151150307.png)]
public class Test04 {
public static void main(String[] args) {
int[] a = {1,2,3,4};
int[] b = a;
int c = 10;
int d;
// System.out.println(d);
System.out.println(a);
System.out.println(b);
System.out.println(a == b);
a[1] = 10;
System.out.println(b[1]);
System.out.println(a);
System.out.println(b);
int x = 1;
int y = x;
}
}
public class Test05 {
public static void main(String[] args) {
int[] a = new int[3];
a[0] = 10;
a[1] = 20;
a[2] = 30;
int[] b = new int[3];
b[0] = 10;
b[1] = 20;
b[2] = 30;
System.out.println(a);
System.out.println(b);
System.out.println(a == b);
int[] c = {1,2};
int[] d = {1,2};
int[] f = new int[2];
f[0] = 1;
f[1] = 2;
System.out.println(c == d);
System.out.println(c == f);
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qJt4egij-1662468874848)(Java学习/image-20220301143826694.png)]
程序计数器:主要是控制线程当中程序的执行性顺序的;
虚拟机栈:我们平常接触到的最多的就是局部变量,局部变量定义的时候必须要给初始值,这是JVM规定的;
堆:存放对象和数组
元数据:常量池(比如字符串常量)、方法元信息、类元信息
声明:
第一种(字符串常量):
String 字符串变量名 = “字符串字面值”;
第二种(字符串对象):
String 字符串变量名= new String(“字符串字面值”);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WFZqL27k-1662468874849)(Java学习/image-20220302103343028.png)]
public class Test01 {
public static void main(String[] args) {
//第一种,创建字符串常量
String s1 = "hello world";
String s2 = "h";
String s3 = " ";
String s4 = "";
String s5 = "我";
String s6 = "china中国";
//第二种,创建字符串对象
String s7 = new String("wukelan");
String s8 = new String("中国");
}
}
字符串拼接:+
1、+在java当中有两种运算方式
加法运算
字符串拼接运算
2、在字符串拼接时,表达式中如果出现了多个+,而且在没有小括号的前提下,遵循从左到右依次运算
如果+左右是数字,做加法运算,如果+左右至少有一个字符串就做拼接运算
public class Test02 {
public static void main(String[] args) {
String s1 = "hello";
String s2 = "world";
String s3 = s1 + s2;
System.out.println(s3);
String s4 = s1 + 10;
System.out.println(s4);
String s5 = s1 + 10 + 20;
System.out.println(s5);
String s6 = 10 + 20 + s1;
System.out.println(s6);
String s7 = 10 + (20 + s1);
System.out.println(s7);
}
}
字符串比较的两种方式,特别是字符串拼接的比较
/*
* 字符串比较:
* 1、== 比较的是地址
* 2、equals 比较的是字符串值(字面值)
* */
public class Test03 {
public static void main(String[] args) {
String s1 = "hello";
String s2 = "world";
String s3 = s1;
String s4 = "hello";
String s5 = new String("hello");
String s6 = new String("hello");
String s7 = "helloworld";
//先创建一个字符串对象,然后将两个字符串值拼接,去常量池搜索
//拼接后的字符串,如果存在,将对象的地址指向该字符串常量池地址
//然后,将对象的地址给到s8
String s8 = s1 + s2;
//先拼接字符串,然后去常量池搜索拼接后的字符串,如果存在
//直接将该常量池当中的字符串地址指向s8
String s9 = "hello" + "world";
String s10 = s1 + "world";
String s11 = "hello" + new String("world");
System.out.println(s1==s2);
System.out.println(s1 == s4);
System.out.println(s1 == s5);
System.out.println(s5 == s6);
System.out.println(s7 == s9);
System.out.println(s7 == s8);
System.out.println(s7 == s10);
System.out.println(s7 == s11);
System.out.println("=========================");
System.out.println(s1.equals(s4));
System.out.println(s7.equals(s8));
System.out.println(s7.equals(s9));
System.out.println(s1.equals(s2));
}
}
两个string相关的类StringBuffer StringBuilder
/*
* 两个String相关的类
* StringBuffer 线程安全
* StringBuilder 非线程安全
* */
public class Test04 {
public static void main(String[] args) {
//+和append的区别,+如果是字符串对象的拼接需要每次都要创建一个对象
//StringBuffer.append不需要每次创建对象
StringBuffer s1 = new StringBuffer("hello");
//追加
s1.append("world");
String s2 = new String("hello");
String s3 = s2 + "world";
String s4 = s3 + "1111";
System.out.println(s1);
s1.reverse();
System.out.println(s1);
StringBuffer s5 = new StringBuffer("123456");
s5.delete(1, 2);
System.out.println(s5);
StringBuilder s6 = new StringBuilder("hello");
System.out.println(s6);
s6.reverse();
String s7 = "abcdef";
System.out.println(s7.charAt(4));
System.out.println(s7.substring(0, 4));
}
}
方法:将java当中某一特定的功能抽取出来,包含在大括号内,这样的形式成为方法;
方法的使用在java当中叫做调用。
方法的定义:
[修饰符列表] 返回类型 方法名(形参列表){
方法体;
return 对应的数据类型;(当有返回值时使用)
}
1、修饰符列表:
方法中的修饰符可以有多个
现在先统一用public static,至于为什么后边讲解
2、返回类型
a、当方法不需要返回结果时,返回类型定义为void(空)
b、当方法需要返回结果时,放回类型可以为基本数据类型、引用数据类型,结合return使用,
也就是return返回的类型必须要和方法定义的返回类型保持一致;
而且,方法体中代码终止的地方必须要有return
方法体中不能出现不可到达的代码,否则编译不通过
3、方法名(标识符):
命名规范:见名知意,尽量使用动词,使用英文,多个单词的话首字母小写其余大写
4、形参列表(可以没有,也可以有多个)
形参:方法当中定义的参数列表
实参:调用方法时传入的实际的值(字面值)
注意:形参的类型可以为基本数据类型,引用数据类型
在方法调用的时候,形参和实参必须保持一致(类型一致,个数一致、顺序一致),方法中 形参类型跟变量名无关
/*
* 方法的定义和使用
* */
public class Test02 {
public static void main(String[] args) {
int result = sum(10,20);
System.out.println(result);
print(10,20);
System.out.println(getMax(5,6));
}
/*
* 求和运算
* */
public static int sum(int a, int b) {
return a + b;
}
/*
* 打印a*b的结果
* void也是一种类型,代表空
* */
public static void print(int a, int b) {
System.out.println(a*b);
// return;
}
/*
* 比较两个整数的大小,返回大的值
*
* */
public static int getMax(int a, int b) {
if(a > b) {
return a;
}else {
return b;
}
}
/*
* 1-10之间找7
* */
public static int getSeven() {
for(int i = 1; i <= 10; i++) {
if(i == 7) {
return i;
}
}
return 0;
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5aFCGIzB-1662468874850)(Java学习/image-20220303210550212.png)]
/*
* 形参和实参
* */
public class Test03 {
public static void main(String[] args) {
//1、形参实参必须类型一致
//20 "10"就是实参,使用或调用方法时传入给到的参数
//sum方法当中 a b形参
//int result = sum("10",20);
//2、个数一致
//String result1 = append("100", 20, 30);
//3、顺序一致
//String result2 = append(10, "20");
long a = 100;
long b = 1000000000000L;
//自动类型转换
long result3 = mutiple(20,30);
//传递的是数组的地址,在调用testArr的时候,这个方法根据
//形参接收到数组的地址,然后根据地址找到对应的数组,
//将数组存放在堆当中的数组数据改变了,
//但是实际array指向的地址没有被改变
//那么main方法中调用testArr结束的时候,
//还是根据地址去堆里找之前存放的数组,
//这个时候第二个位置的数被改变了
int[] array = {0,1,2,3};
System.out.println(array);
testArr(array);
System.out.println(array[1]);
//int d 是main当中的参数,调用add的时候传递的实参是值
//add方法中用形参接收,改变形参的值对main当中的d没有影响
int d = 10;
add(d);
System.out.println(d);
}
/*
* 求和
* */
public static int sum(int a, int b) {
return a + b;
}
/*
* 拼接字符串
* */
public static String append(String a, int b) {
return a + b;
}
/*
* 乘法
* */
public static long mutiple(long a, long b) {
return a * b;
}
/*
*改变数组第二个位置的数
* */
public static void testArr(int[] a) {
a[1] = 10;
}
public static void add(int a) {
a = a + 1;
}
}
/*
* 方法当中定义变量(局部变量)必须要给初值值
* */
public class Test04 {
public static void main(String[] args) {
}
/*
* 打印
* */
public static void print() {
int a = 0;
System.out.println(a);
//b没有初始值程序报错
//int b;
//System.out.println(b);
}
}
/*
* 方法相互调用
* 1、方法当中可以调用方法,但是不能嵌套方法,跟ifelse for循环不一样
* 2、方法在类当中的位置没要求
* 3、方法相互调用可能会有问题,可能会有栈溢出的问题
* 4、递归调用(尽量不要写)
* 5、方法调用遵循栈的原则(子弹匣),先进后出
*
* */
public class Test05 {
public static void main(String[] args) {
System.out.println("+++++++++");
method1();
System.out.println("==============");
}
public static void method1() {
System.out.println("method1 start");
method2();
System.out.println("method1 end");
}
public static void method2() {
System.out.println("method2 start");
System.out.println("method2 end");
//method1();
}
//递归调用
public static void method3() {
method3();
}
}
面向过程:整个系统由一个主方法去完成,然后如果某一环节出问题,其他环节都受到影响。
这样,系统的耦合度(程序和程序之间关联度)非常高,复用率非常低。
涉及一些小的系统的时候,面向过程还是有优势的,效率要高。
面向对象:整个系统由主方法去完成对象和对象之间的相互合作,这样的话,可以极大的提高代码
复用率,以及降低系统的耦合度。
概念:客观世界不存在的东西,就是看不见摸不着的东西,他是一个抽象的概念,在java当中就是一个模板。
抽象:将很多事物具有共性提取出来给出一个概念,这是一个抽象的过程。
类—>对象的过程,在java当中叫实例化
对象—>类的过程,在java当中叫抽象
[修饰符列表] class 类名 {
类体;
}
修饰符列表: public,用它修饰类的时候类名要和文件名必须保持一致
abstract final等也可作为类的修饰符
类名:参考标识符规范去定义
类体:包括属性和方法
属性:用变量表示
变量(成员变量):包括实例变量和静态变量
实例变量:变量的访问需要创建实例
静态变量:后边补充…
方法:实例方法和静态方法
[修饰符列表] 返回类型 方法名(参数列表){
方法体
}
public class Student {
/* 1、属性用变量表示
2、可以为基本数据类型也可以为引用数据类型
3、引用数据类型,他就是一个变量,指向的是一个内存地址
比如String,所有java当中的class都是引用数据类型,
当前我们所在的Student就是引用数据类型
4、int age是实例变量,它属于对象,只能通过对象访问,
或者访问它的时候必须要经过类-对象的实例化过程
5、类体当中的变量可以没有初值,系统会给默认值,
一切向0看齐
整型->0
浮点型->0.0
引用数据类型->null
6、类体当中,在方法之外的变量统一叫做成员变量
方法体中的变量叫做局部变量
*/
int age;
boolean sex;
int stuId;
/*
* 引用数据类型
* */
String name;
//方法后边补充
}
什么是对象:客观世界真是存在的物体,看的见摸得着的。
创建对象:
类名 引用变量名 = new 类名();
访问类的变量和方法
访问变量: 引用变量名.实例变量名
给实例赋值: 引用变量名.实例变量名 = 字面值
比如如下代码(Test02):
访问方法:引用变量名.方法名(实参列表)
public class Test02 {
public static void main(String[] args) {
//类-对象的过程,实例化,需要使用new关键字
//new Student()就是一个对象
//peng是一个引用,指向的是这个对象的内存地址
//.简单理解为"的"意思
Student peng = new Student();
System.out.println(peng.age);
System.out.println(peng.name);
peng.age = 10;
peng.name = "xiaopeng";
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZvMPrI4C-1662468874851)(Java学习/image-20220307192348504.png)]
上图片代表了一个Test03当中通过Fruits类实例化出一个banana的过程。
public class Fruits {
int weight;
String color;
String taste;
double price;
}
public class Test03 {
public static void main(String[] args) {
//前后两个banana是两个不同对象的引用地址
//每new一次就要在堆内存中开辟一个对象空间,所以前后打印的内容是不一样的
Fruits banana = new Fruits();
System.out.println(banana);
banana = new Fruits();
System.out.println(banana);
}
}
方法的定义:
[修饰符列表] 返回类型 方法名(参数列表){
方法体;
return 对应方法的返回类型;(返回不为空的时候)
}
类当中的方法:
实例方法(需要创建对象才能访问)
如何调用: 引用变量名.方法名(实参列表)
静态方法
/*
* 先掌握方法的定义和调用,其他可以选择性放弃
* 能定义出来,能传值,能.调用出来,能接收返回值就可以了
* */
public class Cat {
//属性
int age;
String color;
String sex;
int weight;
//方法
//public static修饰词,可以没有
//静态方法
public static void sing() {
System.out.println("喵喵喵.........");
}
//实例方法,需要通过对象才能使用
public void catchMouse() {
System.out.println("抓老鼠.......");
}
//方法当中的参数可以为基本数据类型也可以为引用数据类型
//引用是一个变量,变量指向的是一个内存地址
public void eatFish(int fishNum) {
System.out.println("一顿能吃" + fishNum + "只鱼!");
}
public void eatFoods(String foodName) {
System.out.println("猫在吃" + foodName);
}
public void eatMouse(Mouse mouse) {
System.out.println("猫吃了一个" + mouse.name);
}
public void drink(int num) {
System.out.println("猫一次喝了2L水!");
num = num - 2;
}
public void eating(Food food) {
System.out.println("猫吃了十斤猫粮");
food.weight = food.weight - 10;
}
/*
* 方法返回值:可以为基本数据类型和引用数据类型
* 根据传进来的星期数,返回能睡几个小时
* */
public int canSleepHours(String weekOfday) {
if(weekOfday.equals("星期一")) {
return 2;
}else {
return 1;
}
}
/*
* 返回引用数据类型
* */
/*
public Wief getWief(int age, int sex) {
return xiaoHong;
}*/
}
测试类
public class Test01 {
public static void main(String[] args) {
Cat cafeCat = new Cat();
cafeCat.color = "咖啡色";
cafeCat.sex = "男";
cafeCat.catchMouse();
//方法传参,传递基本数据类型
cafeCat.eatFish(3);
//Cat.sing();
//cafeCat.sing();
//方法传参,传递引用数据类型
cafeCat.eatFoods("饼干");
//需要定义一个引用变量,然后引用变量指向一个具体的mouse对象
//调用eatMouse的时候将引用传递过去
//注意:这个地方是传的引用,也就是地址,地址是指向的对象的地址值
Mouse jerry = new Mouse();
jerry.name = "jerry";
cafeCat.eatMouse(jerry);
//传参改变的问题
//1、参数为基本数据类型,传递的是实际的数值
//传过去的值其实又被重新复制了一份
int cupWater = 10;
cafeCat.drink(cupWater);
System.out.println(cupWater);
//2、传递引用数据类型
//传递的是对象的地址,改变了地址指向的对象的属性值,都会受到影响
Food cafeFood = new Food();
cafeFood.weight = 20;
cafeCat.eating(cafeFood);
System.out.println(cafeFood.weight);
//返回值
int result = cafeCat.canSleepHours("星期二");
System.out.println(result);
}
}
重载:也叫overload,就是一个类当中可以有相同方法名但参数列表不同的方法,这种现象叫做重载。
作用:方便调用者使用,在使用的时候就像是在使用同一个方法,其实本质不是一个。
什么时候用到重载:多个方法的功能相似的时候可以考虑。
重载的条件: 1、方法名相同(区分大小写)
2、形参不同(类型、个数、顺序不同)
注意:跟方法的返回类型无关
public class Calcuator {
public int sum(int a, int b) {
System.out.println("int.........");
return a + b;
}
//不行,这里是方法重复而不是重载了
// public int sum(int c, int d) {
// System.out.println("int.........");
// return c + d;
// }
public int sum(int a, int b, int c) {
System.out.println("int.........");
return a + b + c;
}
public double sum(double a, double b) {
System.out.println("double.........");
return a + b;
}
public float sum(float a, float b) {
System.out.println("float...........");
return a + b;
}
}
包的作用:用来限制类的使用或者访问,有可能在一个项目当中不同包下有相同的类,但是相同名称的类包含的属性和方法可能不一样,需要使用哪个方法就要对应选择导入(import)相应的类。
注意:如果选的是同一包下的类,就不需要导包(import)。
import java.util.Scanner
import是导入的意思,java.util.Scanner这是一个全限定类名,java.util是包路径 Scanner是类名
1、this在java当中是一个关键字,是这个的意思,用来表示指向当前对象的引用。
什么是引用? 引用是一个变量,变量指向的是一个内存地址
2、每创建一个对象就有一个相应的this
3、this关键字一般出现在实例方法或者构造方法中,用来表示执行此方法的当前对象。
public class Flower {
int high;
public Flower() {
System.out.println("++++++++++=");
}
public void water() {
System.out.println("water========" + this);
high = high + 1;
}
public static void shiFei() {
//报错,因为this是对象级别的变量,不能出现在static方法当中
//this;
}
}
public static void main(String[] args) {
Flower xiLanHua = new Flower();
System.out.println(xiLanHua);
xiLanHua.high = 10;
xiLanHua.water();
System.out.println(xiLanHua.high);
Flower rose = new Flower();
System.out.println(rose);
rose.high = 20;
rose.water();
System.out.println(rose.high);
}
1、构造方法,又叫做构造器、Constructor
2、作用:创建对象,给对象属性赋值
3、构造方法的定义:
[修饰符列表] 当前的类名(形参列表){
构造方法体;
}
注意:构造方法是没有返回类型的,即使是void也不能加
4、构造方法有两种
a、形参列表有参数叫做有参构造,
b、无参数叫做无参构造,又叫做空构造
5、
a、如果类当中没有声明构造方法,其实是有一个默认的无参构造;
b、如果类当中声明了构造方法(不管有参无参),系统不会再默认有一个无参构造了!!!
如果想要调用无参构造创建对象必须显示在类当中声明出来;
public class User {
String name;
int age;
//无参构造
public User() {
System.out.println("调用无参构造.....");
}
//有参构造
public User(String a, int b) {
// System.out.println("调用有参构造......");
this.name = a;
this.age = b;
}
}
public static void main(String[] args) {
User zhangSan = new User();
User liSi = new User("李四", 20);
//sum(1,2);
//sum(1.2,1.3);
User wangP = new User();
wangP.age = 20;
wangP.name = "wangp";
User dongH = new User();
dongH.age = 18;
dongH.name = "dongH";
User liSiY = new User("lSY",20);
}
1、静态变量,用static修饰符修饰的变量,它是类级别的变量,使用的时候通过 类名.变量名
比如:American.nation
所谓的类级别的变量是指,定义在这个类当中的某个属性只会有一个值,比如国家的国籍问题
一般情况下这种变量被定义为 static final的
2、实例变量,所谓的实例就是指对象,对象级别的变量,只能通过创建对象访问。
public class American {
//实例变量,对象级别的属性
int carId;
//类级别的属性
final static String nation = "美国国籍";
public static void eat() {
System.out.println("吃饭.........");
}
}
public static void main(String[] args) {
// American.nation = "美国国籍";
American teLangPu = new American();
teLangPu.carId = 1001;
System.out.println(teLangPu.nation);
// teLangPu.nation = "美国国籍";
American baiDeng = new American();
baiDeng.carId = 1002;
// baiDeng.nation = "中国国籍";
System.out.println(baiDeng.nation);
American aoBaMa = new American();
aoBaMa.carId = 1003;
// aoBaMa.eat();
// aoBaMa.nation = "美国国籍";
System.out.println(aoBaMa.nation);
//静态变量使用的时候要用 类.静态变量名,不能用对象
System.out.println(American.nation);
American.eat();
}
静态方法主要是掌握:静态方法中不能直接访问实例变量、实例方法,如果非要访问必须要创建对象。
静态方法以后主要是用在工具类中,现在不常用,所以以后定义方法大部分还是实例方法。
/*
* 变量
* 类{
* 属性:变量
*
* 方法:
*
* }
*
* 1、变量:成员变量和局部变量
* a、成员变量:定义类体当中方法之外的变量
* 分为:实例变量和静态变量
* 实例变量:对象级别的变量,需要依赖对象来访问
* 静态变量:类级别的变量,比如美国人类的国籍,男人类的性别,
* 这种取决于当前类的变量可以用静态变量来定义。
* b、局部变量:方法体当中声明的变量
* 方法体当中声明的局部变量,必须要给默认值、初值(系统规定的)
* 方法当中的形参变量,也可以认为是局部变量
* 2、方法:实例方法和静态方法
* 实例方法:对象级别的方法,需要创建对象才能调用,
* 通过"引用."的方式调用
* 静态方法:类级别的放法,无需创建对象,
* 通过"类名."的方式调用
*
* 注意:a、静态方法中不能直接访问实例变量、实例方法,
* 因为实例变量和方法都是对象级别的,
* 而静态是类级别的不需要创建对象就可以调用
* 这与实例变量、方法相悖
* b、如果非要访问实例变量或者调用实例方法就需要
* 在静态方法中创建对象
* c、实例方法当中可以访问实例变量、静态变量
* 也可以调用实例方法、静态方法
* d、什么时候用静态方法?什么时候用实例方法?
* 一般静态方法用在工具类当中。
* 实例方法:比如考试这个行为,每个人考试的成绩是不同的,是具体到对象上的一种行为
* 就可以用实例方法表示。
* */
public class Man {
//实例变量
int age;
//静态变量
static String sex = "男";
//实例方法
public void method(int d) {
age = 10;
//c是局部变量
int c = 0;
System.out.println(d);
}
//静态方法
public static void method2() {
System.out.println("====");
Man wo = new Man();
wo.age = 10;
// age = 10;
sex = "女";
}
public void method3() {
method(1);
method2();
age = 10;
sex = "男";
}
public static void main(String[] args) {
// method();
// age = 10;
Man man = new Man();
Man.method2();
man.method2();
}
}
封装:在java当中将一些信息隐藏起来,限制它的访问。
在java当中主要是通过访问修饰符来限制的
修饰符 同类 同包不同类 子类 (后边补充) 不同包不同类
public true true true true
protected true true true false
无修饰符 true true false false
private true false false false
public class Person {
//关于以下几个修饰符最常用的public private
public int age;
protected String name;
boolean sex;
private int high;
private void printAge() {
age = 10;
name = "111";
sex = false;
high = 120;
}
public void test() {
printAge();
}
}
java当中最常用的一种封装方式是,将类当中的属性设置为private私有属性,然后通过生成对应的get/set方法访问属性。
生成的get/set方法一般都要按照开发规范来定义,比如方法名setName getName都是get/set加上对应的属性名首字母大写开头
具体以下代码为例
public class Person {
private int age;
private String name;
//set get
//set是设定,可以认为是赋值
//get是获取,可以认为是取值
public void setAge(int age) {
if(age > 0 && age <= 100) {
this.age = age;
}else {
System.out.println("年龄不合法!");
}
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
public void setName(String name) {
if(name.length() < 4) {
this.name = name;
}else {
this.name = name.substring(0, 3);
}
}
}
public class PersonTest {
public static void main(String[] args) {
Person liMing = new Person();
liMing.setAge(10);
System.out.println(liMing.getAge());
liMing.setName("我是李明");
System.out.println(liMing.getName());
}
}
1、继承:现实生活当中存在这样的场景,父亲拥有的东西,儿子可以不用再奋斗了,儿子可以直接继承父亲的财产。
2、在java当中的作用:
可以提高代码的复用性
体现在覆盖和多态方面(没有继承就没有多态)
3、怎么实现继承:用关键字 extends
public 子类名 extends 父类名{
类体
}
4、关于继承,在java当中只能单继承,一个子类只能有一个父类,也就是不能出现这种现象
public A extends B,C{}
但是可以间接继承,
publi A extends B , public B entends C
这个时候A间接继承C
5、public A extends B{}
A叫做子类,派生类、衍生类
B叫做父类、基类、超类
在java当中有祖宗类叫Object,所有的类都默认继承它,只要是定义的类都拥有Object的一些属性和方法
6、私有属性和方法不能被子类直接访问(可以通过父类的get、set方法访问)
继承的好处?
能提高代码的复用性,父类当中拥有的方法和属性,子类当中就不需要再定义了,
如果子类当中继承过来的方法一定要改造一下,这时候就需要重写的机制
public class Parent {
public int money;
public Parent() {
System.out.println("父类构造方法......");
}
public void method() {
System.out.println("Parent method....");
}
}
public class Child extends Parent{
public Child() {
System.out.println("子类构造方法.....");
}
}
public class ChildTest {
public static void main(String[] args) {
Child xiaoMing = new Child();
xiaoMing.money = 100;
xiaoMing.method();
}
}
(1)重写:子类当中有一个和父类当中相同的方法,子类将父类当中的方法重新实现了一下
(2)重写的条件:
1、两个类,类直接存在着继承关系(包括间接继承)
2、方法名相同
3、参数列表相同,和参数名无关
4、返回类型相同,必须严格一致(不存在所谓的自动转型)
5、访问修饰符相同或者子类的访问修饰符权限高于父类的访问修饰符
(3)什么情况下使用重写?重写有什么好处?
当子类继承父类的方法无法满足当前的业务需求时需要重写;
重写可以提高代码的复用性,有了继承和继承重写机制,才有了后边面向对象多态的机制
(4)构造方法不能被重写
(5)自己总结一下方法重载和方法重写的区别??
public class Animal extends Biology{
public int age;
public int high;
public String name;
private int call(int b) {
System.out.println("动物都会叫");
return 2;
}
protected void move() {
System.out.println("动物都会动");
}
// public void eat() {
// System.out.println("动物都会吃......");
//
// }
public int breathe() {
System.out.println("动物都会呼吸.....");
return 1;
}
}
public class Cat extends Animal{
public int tail;//尾巴
public void catchMouse() {
System.out.println("猫都会抓老鼠......");
}
public int call(int a) {
System.out.println("喵喵喵.......");
return 2;
}
public void move() {
System.out.println("猫在动......");
}
// public void method() {
//
// }
// public int method() {
// return 1;
// }
// public int eat() {
// System.out.println("猫都会吃鱼......");
// return 2;
// }
// public byte breathe() {
// System.out.println("猫也会呼吸.....");
// return 3;
// }
public void drink() {
System.out.println("猫也会喝水......");
}
}
public class CatTest {
public static void main(String[] args) {
Cat cafeCat = new Cat();
cafeCat.age = 10;
cafeCat.high = 20;
cafeCat.name = "加菲猫";
cafeCat.tail = 1;
cafeCat.drink();
cafeCat.call(1);
cafeCat.catchMouse();
Tree bigTree = new Tree();
bigTree.drink();
//父类当中的构造方法能不能被重写??
}
}
(1)super是java当中的一个关键字,是一个引用,指向子类当中创建的父类对象
(2)super的用法
1、创建子类对象的时候,调用子类构造方法,会在子类构造方法当中隐式调用父类的构造方法,相当于super();
super()必须要放在方法体的第一行,因为先有父类对象,才有子类对象
2、也可以使用super(实参)调用父类的有参构造
3、当父类当中只声明了有参构造方法,创建子类对象时必须显示调用父类的有参构造,否则会编译不通过;
因为如果不显示调用父类有参构造,系统默认调用父类无参构造,结果父类中没有无参构造(父类中如果声明了无参构造,默认 的无参构造方法就不存在了),所以编译报错。
4、可以使用super. 访问父类的属性和调用父类的方法
(3)为什么子类实例化要调用父类构造方法??
因为子类继承了父类,子类实例化时想要继承父类的属性和方法(实例变量、实例方法),需要有父类对象才能继承,所以要先创建父类对象,创建父类对象就要调用父类的构造方法。
public class Car {
String name;
public void run() {
System.out.println("车都会跑.....");
}
public Car() {
System.out.println("父类构造方法");
}
//
public Car(int a) {
System.out.println("父类有参构造方法......");
}
}
public class BMW extends Car{
int money;
//构造方法不能被重写,因为子类对象不能创建父类对象
// public Car() {
// System.out.println("=====");
// }
// public Car(int a) {
//
// }
public BMW() {
//super();//不加系统会隐式的调用父类的无参构造方法创建父类对象
//加上super就是显示的调用
// super(1);
// super();
// super();
System.out.println("子类的构造方法");
}
}
public class BMWTest {
public static void main(String[] args) {
//BMW是一个类,当然也就是一个引用数据类型
//BMW bmw5是声明了一个BMW类型的引用变量
//bmw5 指向的是一个地址,new BMW这个对象的堆地址
//BMW()是调用子类的构造方法
BMW bmw5 = new BMW();
System.out.println(bmw5);
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t4CE49M0-1662468874852)(Java学习/image-20220314212433327.png)]
1、this和super都是java当中的关键字
2、this是每创建对象的时候就会生成一个相应的this引用,指向当前对象,可以参考上边的内存图
super是创建子类对象的时候,会创建一个父类对象,super是指向的创建的父类对象的引用
3、this()代表调用当前类的构造方法,super()代表调用父类构造方法
this()和super()必须要置于方法体的第一行
4、**this.**可以访问字类的属性和父类的属性,可以调用父类和子类的方法
**super.**可以访问父类的属性和调用父类的方法
1、多态:编译期一种状态,运行时一种状态
2、多态相关的两个概念:转型
2.1 无论是向上转型还是向下转型,两个类型直接必须要存在继承关系,否则会报错类型转换异常!
2.2 向上转型(类似于自动类型转换):父类引用指向子类对象
Animal dog = new Dog();
2.3 向下转型
Cat cat = new Cat();
Animal cat = (Animal)cat;
3、为了防止类型转换异常,可以通过运算符instanceof在转换之前进行类型判断
语法: A instanceof B,结果是一个布尔值,表示A是否是一个B的类型
4、多态有什么好处?
提高代码的扩展力,以后功能需求可能随时变动,没有多态可能需要改动大量的代码,有了多态可能只需要修改几行代码。
public class Phone {
public int price;
public String chip;//芯片
public void call() {
System.out.println("打电话......");
}
}
public class Mi extends Phone{
public void redLine() {
System.out.println("遥控器......");
}
}
public class HuaWei extends Phone{
public String brand;
public String os;
public void nfc() {
System.out.println("刷卡坐公交车.....");
}
public void call() {
System.out.println("防诈骗......");
}
}
public class Test02 {
public static void main(String[] args) {
Phone phone = new Phone();
phone.call();
HuaWei mate5 = new HuaWei();
mate5.call();
// phone.nfc();
mate5.nfc();
System.out.println("===========");
//1、向上转型,子类对象指向父类引用
Phone mate6 = new HuaWei();
//2、向下转型,要慎重!!!可能会出现类型转换异常的错误
HuaWei mate61 = (HuaWei)mate6;
// mate6.brand = "梅特6";
mate6.call();
mate61.nfc();
//类型转换异常,因为Mi类和HuaWei类没有继承关系
// Mi mi11 = (Mi)mate6;
//上边程序报错,程序被中断了,后边的程序就无法继续了
System.out.println("++++++++++");
Phone phone1 = new Mi();
//instanceof是一个运算符
// A instanceof B 结果是一个布尔值
//可以防止强制类型转换的时候出现异常
if(phone1 instanceof HuaWei) {
HuaWei mate7 = (HuaWei)phone1;
mate7.nfc();
}
if(phone1 instanceof Mi) {
Mi mi12 = (Mi)phone1;
mi12.redLine();
}
//Phone引用数据类型
//引用数据类型的默认值是null
//空值强制转换的时候,不会出现转换异常,但是强转之后的变量也是一个null
//后边在使用的时候可能出现空指针异常
Phone phone2 = null;
// phone2.chip = "1111";
HuaWei mate9 = (HuaWei)phone2;
System.out.println(mate9);
mate9.nfc();
}
}
4、通过多态机制实现一个主人养宠物的例子,主人只需关注喂养的是一个宠物,而不需关注具体样的是什么类型的宠物,不同类型的宠物都有吃的行为,但是可能吃的粮食不一定,而主方法(main)不需要关注这些,主方法只关注主人和宠物这两个对象,具体内部的实现机制是通过多态和继承来表现的。
public class Pet {
public String name;
public void eat() {
System.out.println("宠物吃东西......");
}
}
public class Dog extends Pet{
public void eat() {
System.out.println(this.name + "吃狗粮......");
}
}
public class Cat extends Pet{
public void eat() {
System.out.println(this.name + "吃猫粮.....");
}
}
public class Master {
public String name;
public void feed(Pet pet) {
pet.eat();
}
}
public class PetTest {
public static void main(String[] args) {
Master xiaoMing = new Master();
xiaoMing.name = "小明";
Dog haShiQi = new Dog();
Cat cat = new Cat();
Pet pet = new Dog();
pet.name = "哈士奇";
xiaoMing.feed(pet);
System.out.println();
}
}
#####2.9.5.1 什么是异常??
不正常的现象,在代码当中就是我们常见的报错,
Exception: CalassCastException、ArrayIndexOutOfBoundException、NullPointerException、 ArithmeticException
Error: StackOverflowError、OutOfMemoryError
#####2.9.5.2 异常的分类:
运行时异常(非检查异常):
CalassCastException ArrayIndexOutOfBoundException NullPointerException
ArithmeticException
非运行时异常(可检查异常、编译期异常):
FileNotFoundException (IO学习时会使用)SQLException(Jdbc学习时使用)
注意:运行时异常一般情况下不需要处理,用业务逻辑去控制,比如if else,比如类型转换时用
instanceof,空指针异常用非空校验去处理,而不是用trycatch或throws
非运行时异常,尽量自己trycatch 不要throws,这种异常建议必须要处理。
错误(error)StackOverflowError、OutOfMemoryError
解决不了,只能避免,平时写代码尽量不要写死循环、不要写递归。
#####2.9.5.3 处理异常的方式:
1、try catch
try{
可能出现异常的代码块
}catch(异常类){
异常处理代码块;
}
try花括号内的代码一定要是可能出现的代码,不要把所有代码都放在try内
public class Test03 {
public static void main(String[] args) {
int a = 10;
int b = 0;
//不加trycatch 是由jvm来处理的,程序会被中断,
//不会继续往下进行了
System.out.println(a / b);
//加了trycatch是我们自己手动处理了异常,没有交给jvm,程序不会中断
try {
//可能有问题的代码块;
System.out.println(a / b);
}catch(ArithmeticException e) {//catch(异常类)
//异常处理代码块
//printStackTrace是自己手动打印的信息虽然跟jvm报错信息一样,
//但是机制不一样
e.printStackTrace();//打印异常信息,异常类自带的方法
// System.out.println("分母不能为0!");
}
System.out.println(a + b);
}
}
2、throws
方法名 throws 异常类(){
方法体;
}
2.1 throws类似于现实生活当中的甩锅,推卸责任,所以尽量少用
2.2 如果方法一致往上throws,最终还是要交给JVM所以不建议
2.3 假如方法A throws一个异常,表示这个方法有问题,类似于我们生活当中,
你用我的东西可以但 是可能有问题,要么你自己处理,要么你再甩(throws)给别人
public class Test05 {
public static void main(String[] args) {
}
public static void test() throws FileNotFoundException {
//查找对应路径下的文件
FileInputStream file = new FileInputStream("D:/11.txt");
}
public static void test1() throws FileNotFoundException {
test();
}
}