java笔记

Java学习笔记

1、java基础

1.1 java关键字和标识符

关键字:
    一般是编译器(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
    	  
    
    

1.2 字面值

字面值:java当中的数据,java语言组成部分,跟关键字、标识符一样
    10100-200 整数
    1.2 -1.2 浮点数
    truefalse 布尔值
    'A' 'b' '我' 字符
    “LiMing” 字符串

1.3 基本数据类型

计算机的一些常识
    byte kb mb gb tb
    1kb = 1024b
    1mb = 1024kb
    1gb = 1024mb
    1tb = 1024gb
现在的计算机都是交流电的形式运行的,他只识别所谓的01电信号
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
    
    
    
    
    

1.4 字符

编码:计算机协会规定了一套标准,用来作为计算机和文字之间的一套字典参照表,文字和数字之间的转换表,
    因为计算只认01,单纯的文字计算机解释不了。
解码:计算机按照规定格式的字典参照(编码格式),将存储到计算机内存当中的编码后的二进制文字再解释出来。
编码-解码要按照同一套标准,如果两边标准不一致,就会出现乱码的问题。
    常见的编码格式:AscllGBKUnicode(Utf-8)
    以后开发当中经常用到的编码UTF-8  

如何定义一个字符:
    语法: char 变量名 = 字面值;
		  字面值是用''括起来的字符,字符只能是单个字符,当然转义字符是一种特殊的字符,不要混淆了,其实也是单			个字符。
          如: char char1 = 'A';
              char cahr2 = '我';
			  char char3 = '\u0001';
	转义字符:有一些特殊的字符无法用我们认识的文字表示出来,就规定了可以将常见的字符进行转义,表示出来
        比如
        	\n, 不加\ 就是一个普通的n字符,加了就是回车或换行
        	\t, 不加\ 就是一个普通的t字符,加了就是tab键
            \\ \b \r
        	

1.5 算数运算符

加(+)、减(-)、乘(*)、除(取商/ 取余%)、自增(++)、自减(–)

注意:核心点自增和自减

自增: ++前后都可以放变量

​ 变量在前:先用后本身的值加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.6 赋值运算

= (赋值)

+=(加等于)

-= (减等于)

*=(乘等于)

/= (除等于)

%=(模等于)

注意:

​ 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;
				
	
		
	}
}

1.7 关系运算符

表达式:变量和符号组成的一条式子,它的结果是一个值;

< <= >= ==

表达式和表达式之间可以串联使用

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));
		
	}
}

1.8 逻辑运算符

什么是短路:

​ 在程序当中正常的执行顺序被某个运算符给中断了,一条语句后边程序就不执行(不是不需要)了,

​ 类似于生活中的短路现象。

常用的逻辑运算符:

​ !非

​ &&短路与

​ || 短路或

​ 具体后两种逻辑运算符达短路现象以下程序为例

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.9 三元运算符

语法:

​ 条件表达式 ? 表达式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的类型模糊,不确定是整型还是浮点型,报错
		
	}
}

2.0 运算符的优先级

​ 没有必要去刻意记忆运算符的优先级,最简单的方式就是表达式之间加();

2.1 程序流程控制

2.1.1 选择结构if

三种用法

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("非常优秀");
		}
		
	}
}

2.1.2 switch语句

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;
		}
	}
}

2.1.3 补充

获取键盘输入

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这个整体叫全限定类名

2.1.4 循环结构

注意:写循环一定不要写死循环,比如for(; while(true){} do{}while(true)

2.1.4.1for循环(平时开发最常用)

语法结构:

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);
		
	}

​ 增量表达式位置比较灵活,也可以写在循环体里面

2.1.4.2 while循环(不常用)

语法: 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++;
		}
	}
}

2.1.4.3 do while循环(不常用)

语法: 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先执行循环语句再判断

2.1.4.4 break和continue

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);
			
		}
	}
}


2.2 数组

定义:用来存储多个相同数据类型的数据模型(相同、多个)

声明方式:

​ 第一种: 数据类型[] 数组变量名 = {};

​ {}里面是具体存放的一个对应数据类型的数

​ 例: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);
		
		
	}
}


2.3 JVM内存模型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qJt4egij-1662468874848)(Java学习/image-20220301143826694.png)]

程序计数器:主要是控制线程当中程序的执行性顺序的;

虚拟机栈:我们平常接触到的最多的就是局部变量,局部变量定义的时候必须要给初始值,这是JVM规定的;

堆:存放对象和数组

元数据:常量池(比如字符串常量)、方法元信息、类元信息

2.4 字符串

声明:

第一种(字符串常量):

​ 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));
		
		
	}
	

}

2.5 方法

方法:将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();
	}
}

2、面向对象编程

2.1 面向对象和面向过程

面向过程:整个系统由一个主方法去完成,然后如果某一环节出问题,其他环节都受到影响。

这样,系统的耦合度(程序和程序之间关联度)非常高,复用率非常低。

​ 涉及一些小的系统的时候,面向过程还是有优势的,效率要高。

面向对象:整个系统由主方法去完成对象和对象之间的相互合作,这样的话,可以极大的提高代码

复用率,以及降低系统的耦合度。

2.2 类

概念:客观世界不存在的东西,就是看不见摸不着的东西,他是一个抽象的概念,在java当中就是一个模板。

抽象:将很多事物具有共性提取出来给出一个概念,这是一个抽象的过程。

类—>对象的过程,在java当中叫实例化

对象—>类的过程,在java当中叫抽象

2.2.1 定义

​ [修饰符列表] 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;
	
	//方法后边补充
}

2.3 对象

什么是对象:客观世界真是存在的物体,看的见摸得着的。

创建对象:

​ 类名 引用变量名 = 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);
		
	
	}
}

2.4 方法

方法的定义:

​ [修饰符列表] 返回类型 方法名(参数列表){

​ 方法体;

​ 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);
		
	}
}

2.4.1 方法重载

重载:也叫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;
	}
	
	
	
}

2.5 包(package)

包的作用:用来限制类的使用或者访问,有可能在一个项目当中不同包下有相同的类,但是相同名称的类包含的属性和方法可能不一样,需要使用哪个方法就要对应选择导入(import)相应的类。

注意:如果选的是同一包下的类,就不需要导包(import)。

import java.util.Scanner

​ import是导入的意思,java.util.Scanner这是一个全限定类名,java.util是包路径 Scanner是类名

2.6 this关键字

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);
	}

2.7 构造方法

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);	
		
	}

2.8 静态(static)

2.8.1 静态变量、实例变量

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();
	}
2.8.2 静态方法

静态方法主要是掌握:静态方法中不能直接访问实例变量、实例方法,如果非要访问必须要创建对象。

静态方法以后主要是用在工具类中,现在不常用,所以以后定义方法大部分还是实例方法。

/*
 * 变量
 * 类{
 * 		属性:变量
 * 		
 * 		方法:
 *       
 * }
 * 
 * 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();
	}
	
	
}

2.9 面向对象的三大特征(封装、继承、多态)

2.9.1 封装

封装:在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());
	}
}

2.9.2 继承
2.9.2.1 继承概念

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();
	}
}

2.9.2.2 继承—方法覆盖(重写)

(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();
		
		//父类当中的构造方法能不能被重写??
		
	}
}
2.9.3 super关键字

(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)]

this和super的总结

1、this和super都是java当中的关键字

2、this是每创建对象的时候就会生成一个相应的this引用,指向当前对象,可以参考上边的内存图

​ super是创建子类对象的时候,会创建一个父类对象,super是指向的创建的父类对象的引用

3、this()代表调用当前类的构造方法,super()代表调用父类构造方法

​ this()和super()必须要置于方法体的第一行

4、**this.**可以访问字类的属性和父类的属性,可以调用父类和子类的方法

​ **super.**可以访问父类的属性和调用父类的方法

2.9.4 多态

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 异常

#####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();
	}
}

你可能感兴趣的:(java,笔记,开发语言)