Java基础第一阶段


目录
  • Java代码规范
  • Dos命令
  • 基本数据类型转换
    • 自动类型转换
    • 强制类型转换
    • 字符串转换
  • 运算符
    • 算数运算符
    • 关系运算符
    • 逻辑运算符
    • 赋值运算符
    • 三元运算符
    • 位运算
    • 运算符优先级
  • 标识符命名的规则和规范
    • 标识符的命名规则
    • 标识符命名规范
  • 键盘输入
  • 原码、反码、补码
    • 对于有符号的而言
  • 程序控制结构
    • 顺序控制
    • 分支控制
    • 循环控制
    • break
    • continue
    • return
  • 数组、排序和查找
    • 数组
    • 数组赋值的机制、数组拷贝、数组添加
    • 二维数组的使用方式
  • 面向对象编程(基础部分)
    • 类与对象
    • 成员方法
    • 成员方法传参机制
    • 重载
    • 可变参数
    • 作用域
    • 构造器
    • this
  • Intellij IDEA
    • 快捷键(ecplise)
    • 模板
  • 访问修饰符
    • 基本介绍
    • 使用注意事项
  • 封装
    • 封装的理解和好处
    • 封装实现步骤
  • 继承(代码复用性)
    • 基本语法
    • 细节问题
  • super关键字
    • 便利与细节
    • super和this的区别
  • 方法重写
    • 注意事项和使用细节
  • 面向对象编程 - 多态
    • 基本介绍
    • 多态的具体体现
    • 多态注意事项和细节讨论
    • Java的动态绑定机制(非常重要)
    • 多态的应用
  • Object类详解
    • equal方法
    • hashCode() 方法
    • toString方法
      • 基本介绍
    • finalize()方法
  • 断点调试
    • 快捷键
  • 类变量和类方法
    • 定义语法
    • 访问方法
    • 类变量使用注意事项和细节讨论
    • 类方法基本介绍
    • 类方法的调用
    • 类方法使用的注意事项和细节讨论
    • 理解mian方法语法
  • 代码块
    • 基本语法
    • 注意事项和细节讨论

?## Java开发注意事项和细节说明

  1. Java源文件以 .java为扩展名。源文件的基本组成部分是类(class),如泵类中的Hello类

  2. Java应用程序的执行入孔是main()方法。有固定的书写格式:public static void main(String[] args){......}

  3. Java语言严格区分大小写。

  4. Java方法有一条条语句构成,每个语句以“;” 结束。

  5. 大括号都是成对出现的,缺一不可。(习惯先写{},再写代码)

    // 这是Java的快速入门,演示java的快速开发
    // 说明代码
    //1.public class Hello 表示Hello是一个类,并且是public公有类
    //2.Hello{}表示一个类的开始和结束
    //3.public static void main(String[] args)表示一个主方法,即我们程序的入口
    //4.main(){} 表示方法的开始和结束
    //5.System.out.println("hello,world~"); 表示输出 hello,world~ 到屏幕
    //6.;表示语句的结束
    
    public class Hello{
    
    	//编写一个main方法
    	public static void main(String[] args){
    		System.out.println("hello,world~");
    	}
    }
    
    class Dog{
        public static void main(String[] args){
             System.out.println("汪汪");
        }
       
    }
    
    class Tigger{
        public static void main(String[] args){
             System.out.println("追鹿");
        }
    }
    
  6. 一个源文件中最多包含一个public类。其他类的个数不限

  7. 如果源文件包含一个public类,则文件名必须按该类名命名

  8. 一个源文件中最多只能有一个public类。其他类的个数不限,也可以将main方法写在非public类中,然后指定运行非public类,这样入口方法就是非public的main方法

Java代码规范

  1. 类、方法的注释要用javadoc的方式来写。
  2. 非Java Doc的注释,往往是给代码的维护者来看的,着重告诉读者为什么这样写,如何修改,注意什么问题。(单行和多行注释)
  3. 使用tab操作,实现缩进,默认整体向右边移动时,用shift+tab整体向左移动。
  4. 运算符和 = 两边习惯性的各加一个空格,如:1 + 2 * 4 + 5 - 8
  5. 源文件使用utf-8编码
  6. 行宽度不要超过80字符
  7. 代码编写 次行风格和行尾风格

Dos命令

  • 相关知识补充:

    相对路径:从当前目录开始定位,形成的一个路径

    绝对路径:从顶级目录d,开始定位,形成的路径

  • 常用的dos命令

    1.查看当前目录有什么内容 dir

    dir d:\abc2\test

    2.切换到其他盘下:盘符号 cd : change directory

    切换到C盘 cd /D c:

    3.切换到当前盘的其他目录中(相对路径和绝对路径) ..\ 表示上一级目录

    cd d:\abc2\test cd .. \ .. \abc2\test

    4.切换到上一级

    cd ..

    5.切换到根目录

    cd \

    6.查看指定的目录下所有的子级目录

    tree d:

    7.清屏 cls

    8.推出Dos exit

基本数据类型转换

自动类型转换

public class AutoConvert {
	 public static void main(String[] args) {
		//自动转换
		int num = 'a';
		double d1 = 80;
		System.out.println(num);
		System.out.println(d1);

		// 1.当多种数据混合计算时,系统自动将所有数据转换成容量最大的数据类型,并计算
		int n1 = 10; //ok
		//float d1 = n1 + 1.1; //错误,结果类型是double
		double d1 = n1 + 1.1; //对,结果类型是double
		float d1 = n1 + 1.1F; //对,结果类型是double


		//2.当我们把精度大的数据类型赋值给精度小的数据类型时,
		//会报错
		int n2 = 1.1 //错误

		// 3.(byte,short)和char之间不会相互自动转换
		//当把书赋给byte时,先判断概述是否在byte范围内,如果是就可以
		byte b1 = 10;  //对,-127到128
		// int n2 = 1;  //n2是int
		// byte b2 = n2; //错误,原因:如果是变量赋值,判断类型。字节不同

		//char c1 = b1; //错误,原因byte不能自动转成char

		//4.byte short char 三者只要出现在计算时首先转换为int类型
		byte b2 = 1;
		short s1 = 1;
		//short s2 = b2 + s1; //错,b2 + s1 => int
		//int s2 = b2 + s1; //,b2 + s1 => int

		//byte b4 = b2 + b3; //错误, =>int

		//5.自动提升原则,表达式结果的类型自动提升为操作数中最大类型
		byte b4 = 1;
		short s3 = 100;
		int num200 = 1;

		float num300 = b4 + s3 + num200; //错误,  ===>double
	}
}

强制类型转换

public class ForceConvert {
	public static void main(String[] args){
		//演示强制类型转换
		int n1 = (int)1.9;
		System.out.println("n1=" + n1);  //1.导致精度损失

		int n2 = 2000;
		byte b1 = (byte)n2;
		System.out.println("b1=" + b1);  //2.导致数据溢出



		//细节1:强转符号只对最近的操作数有效,通常使用小括号提升优先级
		//int x = (int)10 * 3.5 + 6 * 1.5; //编译错误:double -> int
		int x = int(10 * 3.5 + 6 * 1.5);  //(int)44.0 -> 44
		System.out.println(x);

		//细节2:char 类型可以保存int的常量值,但不能保存int的变量值,要强转
		char c1 = 100;
		int m = 100;  //ok
		//char c2 = m; //错误
		char c3 = (char)m; //ok
		System.out.println(c3); //100对应字符d

	}
}

字符串转换

public class StringToBasic {
	public static void main(String[] args){

		//基本数据类型->String

		int n1 = 100;
		float f1 = 1.1F;
		double d1 = 4.5;
		boolean b1 = true;
		String s1 = n1 + "";
		String s2 = f1 + "";
		String s3 = d1 + "";
		String s4 = b1 + "";
		System.out.println(s1 + " " + s2 + " " + s3 + " " + s4);

		//String->对应的机泵数据类型
		String s5 = "123";
		//在oop:讲对象和方法的时候会说
		int num1 = Integer.parseInt(s5);
		double num2 = Double.parseDouble(s5);
		float num3 = Float.parseFloat(s5);
		Long num4 = Long.parseLong(s5);
		byte num5 = Byte.parseByte(s5);
		boolean b = Boolean.parseBoolean("true");
		short num6 = Short.parseShort(s5);

		System.out.println(num1); //123
		System.out.println(num2); //123.0
		System.out.println(num3); //123.0
		System.out.println(num4); //123
		System.out.println(num5); //123
		System.out.println(num5); //123

		//解读s5.charAt(0)得到字符串的第一个字符
		System.out.println(s5.charAt(0));


		//细节1:将String类型转化成机泵数据类型是要确保String类型
		//能够转成有效的数据,如将“123”转成整数,但不能将“hello”转成整数
		String str = "hello";
		int n1 = Integer.parseInt(str);
		System.out.println(n1);
	}
}

运算符

算数运算符

/**
 * 演示算数运算符的使用
 */

public class ArithmeticOperator {

	public static void main(String[] args) {

		System.out.println(10 / 4); //从数学角度看是2.5,实际结果2
		double d = 10 / 4;
		System.out.println(d); //结果是2.0



		// % 取模 ,取余
		// 在Java中% 的本质,看一个公式: a % b = a - a / b * b
		// -10 % 3 => -10 - (-10) / 3 * 3
		// 10 % -3 = 10 - 10 / (-3) * (-3) = 10 -9 = 1
		// -10 % -3 = (-10) - (-10) / (-3) * (-3) = -10 - 9 = -19
		System.out.println(10 % 3); // 1
		System.out.println(-10 % 3); // -1
		System.out.println(10 % 3); // 1
		System.out.println(10 % 3); // 1
		//a%b 当a是小数时,公式 = a - (int)a / b * b
		System.out.println(-10.5 % 3); // -1.5

		//++的使用
		//
		int i = 10;
		i++; //自增 == i = i + 1; ==> 11
		++i; //自增 <==> i = i + 1; => 12
		System.out.println("i=" + i); // 12

		/*
		作为表达式使用
		前++:先自增后赋值
		后++:i++先赋值后自加
		*/
		int j = 8;
	//	int k = ++j; //等价j = j + 1; k = j; 
		int k = j++; //等价j = j; j = j + 1; 
		System.out.println("k = " + k + "j =" + j);//8 9

		//面试题1
		int m = 1; 
		m = m++;	//规则使用零食变量:temp = i; i = i + 1; i = tmep;
		System.out.println(m); // 1

		//面试题2
		int i = 1;
		i = ++i; //规则使用零时变量:i = i + 1; temp = i; i = temp
		System.out.println(i);
	}
}

关系运算符

逻辑运算符

ator {
	public static void main(Stirng[] args){
		//&& 和 &案例演示
		int age = 50;
		if (age > 20 && age < 90) {
			System.out.println("ok100");
		}
		

		//& 逻辑与使用
		if (age > 20 & age < 90) {
			System.out.println("ok200");
		}

		//区别
		int a = 4;
		int b = 9;
		//对于&&短路与来说,如果第一个条件为flase,后面的条件不再判断
		//对于&逻辑与来说,如果第一个条件为flase,后面的条件还是判断
		if (a < 1 && ++b < 50) {
			System.out.println("ok300");
		}
		System.out.println("a = " + a + "b = " + b); //4 9
		

		// if (a < 1 & ++b < 50) {
		// System.out.println("ok300");
		// }
		// System.out.println("a = " + a + "b = " + b); //4 10

		//&& 和 &案例演示
		int age = 50;
		if (age > 20 || age < 90) {
			System.out.println("ok100");
		}
		

		//& 逻辑与使用
		if (age > 20 | age < 90) {
			System.out.println("ok200");
		}

		//区别
		int a = 4;
		int b = 9;
		//对于||短路或来说,如果第一个条件为true,后面的条件不再判断
		//对于&逻辑或来说,如果第一个条件为true,后面的条件还是判断
		if (a < 1 || ++b < 50) {
			System.out.println("ok300");
		}
		System.out.println("a = " + a + "b = " + b); //4 9
		

		// if (a < 1 | ++b < 50) {
		// System.out.println("ok300");
		// }
		// System.out.println("a = " + a + "b = " + b); //4 10





		//!和^案例演示
		//!操作是取反 T-》F,F->T
		System.out.println(60 > 20); //T
		System.out.println(!(60 > 20)); //F

		//a^b: 叫逻辑异或,当a和b不同时为真,相同时为假
		boolean b = (10 > 1) ^ (3 > 5);
		System.out.println("b = " + b); //T

	}
}

赋值运算符

public class AssignOperator {
	public static void main(String[] args){

		int n1 = 10;
		n1 += 4; //n1 = n1 + n4
		System.out.println(n1); //14
		n1 /= 3;


		// 赋值运算符的特点
		// (1)运算顺序从右往左
		// (2)赋值运算符的左边只能是变量,右边可以是变量、表达式、常量值
		int num = 20;
		int num2 = 78 * 34 - 10;
		int num3 = a;

		// (3)复合赋值运算符等价于
		int a += 3;  //a = a + 3;

		// (4)复合赋值运算符会进行类型转换
		byte b = 2;
		b += 2; // 等价于 b = (byte)(b + 2);
		b++; // b = (byte)(b + 1);

	}
}

三元运算符

// 基本语法: 条件表达式?表达式1:表达式2;
// 运算条件:
// (1)如果条件为true,运算后结果为表达式1
// (2)如果条件为Flase,运算后结果为表达式2 

public class TernaryOperator {

	public static void main(String[] args) {
		// int a = 10;
		// int b = 99;

		// int result = a > b ? a++ : b--;
		// System.out.println("b = " + b + " result = " + result + " a =" + a); // 100 99 10


		// // 三元运算符细节:
		// //细节1:表达式1和表达式2为可以赋给接受变量的类型(为自动转换/或者强制转换)
		// int a = 3;
		// int b = 8;
		// int c = a > b ? (int)1.1 : (int)3.4;  //可以的
		// double d = a > b ? a : b + 3;  //可以的,满足int -> double

		// //细节2:三元运算符可以转换为if -- else 语句



		// //案例:实现三个数的最大值
		// int n1 = 55;
		// int n2 = 33;
		// int n3 = 123;
		// //思路:
		// //1.先得到n1 和 n2 中最大数,保存到  max1
		// //2.然后再求出max1 和 n3 中最大书,保存到max2

		// int max1 = n1 > n2 ? n1 : n2;
		// int max2 = max1 > n3 ? max1 : n3;
		// System.out.println("最大数= " + max2);

		// //使用一条语句
		// int max = (n1 > n2 ? n1 : n2) > n3 ? 
		// 			(n1 > n2 ? n1 : n2) : n3 
		// System.out.println("最大数= " + max);

	}

}

位运算

// 位运算public class BitOperator {	public static void main(String[] args) {		// >>,<<和>>>运算规则:		//1.算术右移>>:低位溢出,符号位不变,并用符号位补溢出位		//2.算数左移<<:符号位不变,低位补0		//3.>>>逻辑右移,也叫无符号右移,运算规则:低位溢出,高位补0		System.out.println(1 >> 2); //0		System.out.println(1 << 2); //4		System.out.println(4 << 3); // 4* 2 * 2 *2 = 32		System.out.println(15 >> 2); //15 / 2 / 2 = 3	}}

运算符优先级

标识符命名的规则和规范

标识符的命名规则

  1. 由26个英文字母大小写组成,0-9,_和$组成
  2. 数字不能开头
  3. 不能使用关键字和保留字,但能包含关键字和保留字
  4. 区分大小写,长度无限制
  5. 标识符中不能含有空格

标识符命名规范

  1. 包名:多单词组成是所有字母都是小写,如:aaa.bbbb.ccc//com.hsp.crm
  2. 类名、接口名:多单词组成时,所有单词的首字母大写:XxxYyyZzz[大驼峰] 如:TankShotGame
  3. 变量名、方法名:多单词组成时,第一个单词首字母小写,,第二个单词开始每个单词首字母大写:xxxYyyZzz【小驼峰】如:thankShotGame
  4. 常量名:所有字母都是大写。多单词时每个单词用下划线连接:XXX_YYY_ZZZ 如:TAX_RATE

键盘输入

import java.util.Scanner; //表示把java.util下的Scanner类导入public class Input {	public static void main(String[] args) {		//演示接受用户的输入		//步骤		//1.引入/导入 Scanner类所在的包		//2.创建Scanner对象,new创建一个对象		//myScanner就是Scanner类的对象		Scanner myScanner = new Scanner(System.in);		//3.接收用户输入,使用相关的方法		System.out.println("请输入名字");		String name = myScanner.next();  //接收用户输入		System.out.println("请输入年龄");		String age = myScanner.nextInt();  //接收用户输入		System.out.println("请输入收入");		String sal = myScanner.nextdouble();  //接收用户输入		System.out.println("人的信息如下" + "名字" + name + " 年龄:" + age + " 薪水" + sal);			}}

原码、反码、补码

对于有符号的而言

  1. 二进制的最高位是符号位:0表示正,1表示负数
  2. 正数的原码、反码和补码都是一样
  3. 负数的反码 = 它的原码符号位不变,其他位取反
  4. 负数的补码 = 它的反码+1 ,负数的反码 = 负数的补码 - 1
  5. 0的反码,补码都是0
  6. Java没有无符号数,换言之,Java中的数都是有符号
  7. 计算机运算时,都是以补码的方式运算
  8. 当我们看运算结果时都是看原码

程序控制结构

顺序控制

分支控制

import java.util.Scanner;

public class Lf {

public static void main(String[] args) {	// //(1)单分支	// Scanner myScanner = new Scanner(System.in);	// System.out.println("请输入年龄:");	// int age = myScanner.nextInt();	// //使用if判断,输出对应信息	// if(age > 18) {	// 	System.out.println("可以送入监狱");	// }	// System.out.println("程序继续。。。")	//(2)双分支	 // Scanner myScanner = new Scanner(System.in);	 // System.out.println("请输入年龄:");	 //int age = myScanner.nextInt();	 //使用if判断,输出对应信息	 //if(age > 18) {	 	//System.out.println("可以送入监狱");	 //}else {	 	//System.out.println("你被放过了");	// }	 //System.out.println("程序运行");


	//单分支和双分支练习题	//编写程序,声明2个double变量并赋值。	//判断第一个数大于10.0,且第二个数小于20.0,打印两数之和	// double d1 = 34.5;	// double d2 = 2.6;	// if (d1 > 10.0 && d2 < 20.0) {		// System.out.println("两个数和= " + (d1 + d2));	// }


	//定义两个变量int,判断两者的和,是否能被3又能被5整除,打印提示信息	// int num1 = 10;	// int num2 = 20;	// int sum = num2 + num1;	// if(sum % 3 == 0 && sum % 5 == 0) {		// System.out.println("和可以被整除");	// } else {		// System.out.println("和不能被整除");	// }


	//(3) 多分支	// boolean b = true;	// if (b == flase) {  //如果改成 b = flase 能通过编译吗,结果是	// 	System.out.println("a");	// }else {	// 	if (b) {	// 		System.out.println("b");	// 	}else {	// 		if (!b) {	// 			System.out.println("c");	// 		}else {	// 			System.out.println("d");	// 		}	// 	}	// }



	//(4)嵌套分支(不要超过三层)	// Scanner myScanner = new Scanner(System.in);	// System.out.println("请输入该歌手的成绩:");	// double score = myScanner.nextDouble();	// if (score > 8.0) {	// 	System.out.println("请输入性别:");	// 	char gender = myScanner.next().charAt(0); //获取字符串第一个字符	// 	if (gender == '男') {	// 		System.out.println("你进入男子组");	// 	} else {	// 		System.out.println("你进入女子组");	// 	}	// } else {	// 	System.out.println("你被淘汰");	// }



	//(5) switch 分支结构	// Scanner myScanner = new Scanner(System.in);	// System.out.println("请输入一个字符(a-g)");	// char c1 = myScanner.next().charAt(0);	// //在Java中,只要有值返回,就是一个表达式	// switch(c1) {	// 	case 'a' :	// 		System.out.println("今天是星期一");	// 		break;	// 	case 'b' :	// 		System.out.println("今天是星期二");	// 		break;	// 	default:	// 		System.out.println("字符输入错误");	// }	// System.out.println("退出Switch");


	// 细节1:表达式数据类型,应和case后的常量类型一样,	//或者可以自动转成可以相互比较的类型,如输入的是字符,而常量是int


	//细节2:switch(表达式)中,表达式的返回值必须是:	//(byte,short,int,char,enum[枚举],String)	//double c = 1.1;	//switch(c) {		//编译报错	//	case 'a' :	//		System.out.println("ok1");	//		break;	//	case 'b' :	//		System.out.println("ok2");	//		break;	//	default :	//		System.out.println("ok3");	//}


	//细节3:case语句中的值必须是常量(1,'a'),而不能是变量	//char c = 'a';	//char c2 = 'c';	//switch(c) {	//	case 'a' :	//		System.out.println("ok1");	//		break;	//	case c2 :		//编译报错	//		System.out.println("ok2");	//		break;	//	default :	//		System.out.println("ok3");	//}


	//细节4:default子句是可选的,当没有匹配的case时,执行default
	//细节5:break语句用来在执行完一个case分支后使程序跳出switch语句	//如果没有写break,程序会顺序执行到switch结尾//	char c = 'a';//	char c2 = 'c';//	switch(c) {//		case 'a' ://			System.out.println("ok1");//			//break;//		case 'b' :		//			System.out.println("ok2");			//break;//		default ://			System.out.println("ok3");//	}   //结果为ok1 ok2 ok3}}

循环控制

public class CycleControl {	public static void main(Stirng[] args) {		//(1)for循环控制		for (int i = 1;i <= 10 ;i++ ) {			System.out.println("Hello world" + i );		}		//细节1:循环条件是返回一个布尔值的表达式		//细节2:for(;循环判断条件;)中的初始化和变量迭代		//可以写到其它地方,但是两边的分号不能省		//for (;i <= 10 ;) {		//	System.out.println("Hello world" + i );		//	i++;	//	}		//for (;;) {  //表示无限循环		//	System.out.println("无限循环");		//}		//细节3:循环初始值可以有多条初始化语句,但要求类型一样,并且中间用逗号隔开		//循环变量迭代也可以有多条变量迭代语句,中间用逗号隔开	//	int count = 3;	//	for (int i = 0,j = 0; i < count; i++,j +=2 ) {	//		System.out.println("i=" + i + " j=" + j);	//	}		//(2)while		//细节1:循环条件是返回一个布尔值的表达式		//细节2:while循环是先判断再执行语句		//(3)do while			}}

break

continue

return

数组、排序和查找

数组

import java.util.Scanner;public class Array {	public static void main(String[] args) {		// 数组介绍:数组可以存放多个同一类型的数据。数组也是一种数据类型,是引用类型		//快速入门	//	double[] hens = {3, 5, 1, 3.4, 2, 50};		// double totalWeight = 0;	//	System.out.println("数组的长度:" + hens.length);	//	for (int i = 0; i < hens.length; i++) {			// System.out.println("第" + (i + 1) + "个元素的值" + hens[i]);	//		totalWeight += hens[i];	//	}	//	System.out.println("总体重=" + totalWeight 	//		+ "平均体重=" + totalWeight/hens.length);		//使用方式1-动态初始化		//数据类型 数组名[] = new 数据类型[大小]		//步骤1:创建一个double数组,大小为5	//	double scores[] = new double[5];		//步骤2:循环输入	//	for (int i = 0; i < scores.length; i++ ) {	//		System.out.println("请输入第" + (i + 1) + "个元素的值");	//		scores[i] = myScanner.nextDouble();	//	}		//输出,遍历数组	//	for (int i = 0; i < scores.length; i++ ) {	//			System.out.println("第" + (i + 1) + "个元素的值" + scores[i]);	//	}			//使用方法2-动态初始化		//步骤1:创建一个double数组,大小为5	//	double scores[]; //double[] scores; 声明数组,这时scores是null	//	scores = new double[5];		//步骤2:循环输入	//	for (int i = 0; i < scores.length; i++ ) {	//		System.out.println("请输入第" + (i + 1) + "个元素的值");	//		scores[i] = myScanner.nextDouble();	//	}		//输出,遍历数组	//	for (int i = 0; i < scores.length; i++ ) {	//			System.out.println("第" + (i + 1) + "个元素的值" + scores[i]);	//	}			//使用方式3-静态初始化(知道具体数值)	//	double[] hens = {3, 5, 1, 3.4, 2, 50};		// double totalWeight = 0;	//	System.out.println("数组的长度:" + hens.length);	//	for (int i = 0; i < hens.length; i++) {			// System.out.println("第" + (i + 1) + "个元素的值" + hens[i]);	//		totalWeight += hens[i];	//	}	//	System.out.println("总体重=" + totalWeight 	//		+ "平均体重=" + totalWeight/hens.length);		//细节1:数组是多个相同数据类型的组合	//	int[] arr1 = {1, 2, 4, 2.4, "hello"}; //String ->int 	//	double[] arr1 = {1, 2, 4, 2.4}; //int -> double 		//细节2:数组中元素可以是任何数据类型,包括基本类型和引用类型(String,数组,接口等),但是不能混用		String[] arr3 = {"北京","java"};		//细节3:数组创建后,如果没有赋值,有默认值 int-0,short-0 ,byte-0, float-0.0		//double-0.0, char- \u0000, boolean-false, String-null		//细节4:使用数组的步骤 1.声明数组并开辟空间 2.给数组各个元素赋值 3.使用数组		//细节5:数组的下标是从0开始		//细节6:数组下标必须在指定范围内使用,否则报:下标越界异常		//细节7:数组属于引用类型,数组型数据是对象(Object)	}}

数组赋值的机制、数组拷贝、数组添加

public class ArrayAssign {	public static void main(String[] args) {				//基本数据类型赋值,赋值方式为值拷贝		//n2的变化不会影响n1的值		// int n1 = 10;		// int n2 = n1;		// n2 = 80;		// System.out.println("n1 = " + n1); //10		// System.out.println("n2 = " + n2); //80		//数组在默认的情况是引用传递,赋的值是地址,赋值方式为引用赋值,是一个地址		// int[] arr1 = {1, 2, 3};		// int[] arr2 = arr1;		// arr2[0] = 10;		// //看看arr1的值		// System.out.println("=====arr1的元素值=======");		// for (int i = 0; i < arr1.length ; i++ ) {		// 	System.out.println(arr1[i]);		// }		// //数组拷贝		// int[] arr1 = {10, 20, 30};		// //创建一个新的数组arr2,开辟新的数据空间,大小为arr1.length		// int[] arr2 = new int[arr1.length];		// //遍历arr1,把每个元素拷贝到arr2对应元素的位置		// for (int i = 0; i < arr1.length ; i++ ) {		// 	arr2[i] = arr1[i];		// }	}}

二维数组的使用方式

public class TwoDimensionalArray {	public static void main(String[] args) {				//使用方式1:动态初始化		// int arr[][] = new int[2][3];		//使用方式2:动态初始化		// int arr[][];  //先声明二维数组		// arr = new int[2][3];  //再开空间		// //遍历arr数组		// for (int i = 0; i < arr.length ; i++ ) {		// 	for (int j = 0; j < arr[i].length ; j++ ) {		// 		System.out.print(arr[j][i] + " ");		// 	}		// 	System.out.println(); //换行		// }		//使用方式3:动态初始化-列数不确定		// int[][] arr = new int[3][]; //		// for (int i = 0 ; i < arr.length ; i++ ) { //遍历arr每个一维数组		// 	//给每个一维数组开空间		// 	//如果没有给一维数组new ,那么arr[i]就是null		// 	arr[i] = new int[i + 1];		// 	//遍历一维数组,并给一维数组的每个元素赋值		// 	for (int j = 0; j < arr[i].length; j++) {		// 		arr[i][j] = i + 1;		// 	}		// }		//使用方式4:静态初始化		// int[][] arr = {{1,1,1},{8,8,0},{100}};  //		//细节1:二维数组的声明方式:int[][] y 或者 int[] y[] 或者 int y[][]		//细节2:二维数组实际上由多个一维数组组成,它的各个一维数组的长度可以相同也可以不同	}}

面向对象编程(基础部分)

类与对象

  1. 类是一种数据类型

  2. 对象就是一个具体的实例

    public class Object {	public static void main(String[] args) {				//单独变量解决=> 不利于数据的管理(把一只猫的信息拆解)		//第一只猫的信息		// String cat1Name = "小白";		// int cat1Age = 3;		// String cat1Color = "白色";		// //第二只猫的信息		// String cat2Name = "小花";		// int cat2Age = 100;		// String cat2Color = "花色";		//使用OOP面向对象解决		//实例化一只猫		// Cat cat1 = new Cat();		// cat1.Name = "小白";		// cat1.Age = 19;		// cat1.Color = "白";		// //怎么访问对象的属性		// System.out.pirntln("第一只猫信息" + cat1.Name + " " 		// 	+ cat1.Age + " " + cat1.Color)		//如何创建对象		//1.先声明再创建		//Cat cat;		// cat = new Cat();		//2.直接创建		//类与对象的内存分配机制		// 1.栈:一般存放基本数据类型(局部变量)		// 2.堆:存放对象(Cat,cat,数组等)		// 3.方法区:常量池(常量,比如字符串),类加载信息		// Cat cat1 = new Cat();	//先加载Cat类信息,(方法和属性信息,只会加载一次)		// cat1.Age = 10;		// cat1.Name = "傻猫";	//数据存放在方法区的常量池中,地址放在堆中		// Cat cat2 = cat1;	//把cat1赋给cat2,让cat2指向cat1		// System.out.pirntln(cat1.Age);	}}//使用面向对象的方式来解决养猫问题//定义一个猫类Cat->自定义的数据类型// class Cat {// 	//属性 成员变量 字段// 	//属性可以是基本数据类型,也可以是引用类型// 	//细节1:属性的定义语法同变量,如: 访问修饰符(public,proctected,默认,private) 属性类型 属性名// 	//细节2:属性的定义类型可以是任意类型,包含基本类型或引用类型// 	//细节3:属性如果不赋值,有默认值,规则和数组一致,如:[Person类]// 	String Name; // 	int Age;// 	String Color;// 	double Weight;// 	//行为// }
    

成员方法

  • 方法的调用机制分析

    方法调用小结:

    1. 当程序执行到方法时,就会开辟一个独立的空间(栈空间)
    2. 当方法执行完毕后,或者执行到return语句,就会返回
    3. 返回到调用方法的地方
    4. 返回后,继续执行方法后面的代码
    5. 当main方法执行完毕,整个程序退出

成员方法传参机制

public class Method {	public static void main(String[] args) {				// //方法使用		// Person p1 = new Person();		// p1.speak(); //调用方法		// p1.cal01();		// p1.cal02();		// System.out.println(p1.getSum(10,29));		//编写copyPerson,可以赋值一个person对象,返回复制对象,克隆对象		//注意要求得到新对象和原来的对象是两个独立的对象,只是属性相同		Person p = new Person();		p.name = "milan";		p.age = 100;		MyTools tools = new MyTools();		Person p2 = tools.copyPerson(p);		//p和p2是person对象,但是是两个独立对象		//可以进行比较		System.out.println(p == p2);	}}class Person {	String name;	int age;	//方法(成员方法)	public void speak() {		System.out.println("我是一个好人");	}	public void cal01() {		int res = 0;		for (int i = 0; i <= 1000; i++) {			res += i;		}		System.out.println("计算结果:" + res);	}	public void cal02(int n) {		int res = 0;		for (int i = 0; i <= n; i++) {			res += i;		}		System.out.println("cal02计算结果:" + res);	}	public int getSum(int num1, int num2) {		int res = num1 + num2;		return res;	}	//方法的使用细节 - 返回类型	//细节1:一个方法最多有一个返回值,数组除外	//细节2:返回类型可以为任意类型,包含基本类型或引用类型(数组,对象)	//细节3:如果方法要求有返回数据类型,则方法体中最后的执行语句为return 值;	//并且要求返回数据类型必须和return 的类型一致或兼容	//细节4:如果方法是void,则方法体中可以没有return 语句,或者只写return;	//方法的使用细节 - 形参列表	//细节1:调用带参数的方法,一定对应着参数列表传入相同类型或者兼容类型的参数	//方法使用细节 - 方法体	//细节1: 方法不能嵌套定义}class MyTools {	public Person copyPerson(Person p) {		Person p2 = new Person();		p2.name = p.name;  //把原来对象的名字赋给p2.name		p2.age = p.age;		return p2;	}}
  • 方法的递归

    public class Recurison {	public static void main(String[] args) {		T t1 = new T();		t1.test(4);	//递归的规则	//1.执行一个方法时,就创建一个新的受保护的独立空间(栈空间)	//2.方法的局部变量时独立的,不会相互影响	//3.如果方法中使用的是引用变量(如数组,对象),就会共享该引用类型的数据	//4.递归必须向推出递归的体哦阿健逼近,否则就是无限递归	//5.当一个方法执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁	// //桃子问题:	// 	int day = 1;	// 	int peachNum = t1.peach(day);	// 	if (peachNum != -1) {	// 		System.out.println("第 " + day + "天有" + peachNum + "个桃子");	// 	}		//迷宫问题:		//1.先创建迷宫,用二维数组表示		//2.先规定map数组元素值,0表示可以走,1表示障碍物		// int[][] map = new int[8][7];		// //3.将最上面的一行和最下面的一行,全部设置为1		// for (int i = 0; i < 7; i++) {		// 	map[0][i] = 1;		// 	map[7][i] = 1;		// }		// //4.将最右和最左设置为1		// for (int i = 0; i < 7; i++) {		// 	map[i][0] = 1;		// 	map[i][6] = 1;		// }		// map[3][1] = 1;		// map[3][2] = 1;		// //输出当前地图		// for (int i = 0; i < map.length; i++) {		// 	for (int j = 0; j < map[i].length; j++) {		// 		System.out.print(map[i][j] + "")		// 	}		// 	System.out.println();		// }		// //使用findWay给老鼠找路		// T t1  = new T();		// t1.findWay(map,1,1);		// System.out.println("====找路的情况====");		// for (int i = 0; i < map.length; i++) {		// 	for (int j = 0; j < map[i].length; j++) {		// 		System.out.print(map[i][j] + "")		// 	}		// 	System.out.println();		// }		//汉诺塔问题:// 		T tower = new T();// 		tower.move(2,'A','B','C');		//八皇后问题:		int[][] map = new int[8][8];		for (int i = 0; i < map.length; i++) {			for (int j = 0; j < map[i].length; j++) {				map[i][j] = 0;			}		}	}}class T {	public void test(int n) {		if (n > 2) {			test(n - 1);		}		System.out.println("n=" + n);	}// //猴子吃桃问题:// 	//思路分析:前一天的桃子 = (后一天的桃子 + 1) * 2// 	public int peach(int day) {// 		if (day == 10) { //第十天,只有一个桃子// 			return 1;// 		} else if (day >= 1 && day <= 9) {// 			return (peach(day + 1) +1) * 2;// 		} else {// 			System.out.println("day在1-10");// 			return -1;// 		}// 	}	//迷宫问题:使用递归回溯思想来解决	//1.findWay方法就是专门来找出迷宫路径	//2.找到返回true,否则返回false	//3.map就是二维数组,表示迷宫	//4.i,j就是老鼠的位置,初始化为(1,1)	//5.因为是递归找路0 表示可以走 ,1表示障碍物,2表示可以走通,3表示走过,但是走不通是死路	//6.当map[6][5] = 2 就说明找到通路,就可以结束,否则继续找	//7.先确定老鼠找路策略 下 - 右 - 上 - 左	// public boolean findWay(int[][] map, int i, int j) {	// 	if(map[6][5] == 2) { //说明找到	// 		return true;	// 	} else { 	// 		if (map[i][j] == 0) { //当前这个位置0,说明表示可以走	// 			//我们假定可以走通	// 			map[i][j] = 2;	// 			//使用找路策略,来确定该位置是否真的可以走通	// 			if (findWay(map,i + 1, j)) {  //下	// 				return true;	// 			} else if (findWay(map, i, j+1)) { //右	// 				return true;	// 			}else if (findWay(map,i - 1, j)) { //上	// 				return true;	// 			}else if (findWay(map, i, j -1)) { //左	// 				return true;	// 			} else {	// 				map[i][j] = 3;	// 				return false;	// 			}	// 		} else { //map[i][j] = 1,2,3	// 			return false;	// 		}	// 	}	// }	//汉诺塔问题:	// public void move(int num, char a ,char b ,char c) {	// 	if(num == 1) {	// 		System.out.println(a + "->" +c);	// 	} else {	// 		//如果有多个盘,可以看成两个,最下面和上面所有盘(num - 1)	// 		//(1)先移动所有盘到b,借助c	// 		move(num - 1, a, c, b);	// 		// (2)把最下面的这个盘移动到c	// 		System.out.println(a + "->" +  c);	// 		//(3)再把b塔的所有盘移动到c,借助a	// 		move(num - 1, b, a, c);	// 	}	// }	//八皇后问题:	public void put(int[][] map, int row , int list) {		if (map[row][list] == 0) {			map[row][list] = 1;		}				put(map,row + 1, list);	}			}
    

重载

public class Overload {	public static void main(String[] args) {				MyCalculator mc = new MyCalculator();		System.out.println(mc.calculate());	}	}class MyCalculator {	//两个整数的和	public int calculate(int n1, int n2){		return n1 + n2;	}	public double calculate(int n1 ,int n2) {		return n1 + n2;	}	public double calculate(double n1, int n2) {		return n1 + n2;	}	public int calculate(int n1, int n2, int n3) {		return n1 + n2 + n3;	}	//方法重载细节:	//细节1:方法名相同	//细节2:形参列表不同(形参类型或者个数不同,至少有一样不同,参数名无要求)	//细节3:返回类型:无要求}

可变参数

//可变参数案例public class VarParameter {	public static void main(String[] args) {		//案例演示	}}class HspMethod {	public int sum(int n1, int n2) {		return n1 + n2;	}	public int sum(int n1, int n2, int n3){		return n1 + n2 + n3;	}	public int sum(int n1, int n2, int n3, int n4) {		return n1 + n2 + n3 + n4;	}	//上面三个方法名称相同,功能相同,参数个数不同	//1.int... 表示接受的是可变参数,类型是int,即接受多个int	//2.使用可变参数,将nums当作数组	public int sum(int... nums) {		int res = 0;		for ( int i = 0; i < nums.length; i++) {			res += nums[i];		}		return res;	}	//注意事项和细节	// 1.可变参数的实参可以为数组	// 2.可变参数的本质是数组	// 3.可变参数和普通类型的参数一起放在形参列表,但是可变参数在最后	// 4.一个新参列表中只能有一个可变参数	// 5.可变参数的实参可以为0个或多个}

作用域

  • 全局变量(属性)可以不赋值,直接使用,因为有默认值

  • 局部变量必须赋值后,才能使用,因为没有默认值

  • 注意事项和细节使用

    1. 属性和局部变量可以重名,访问时遵循就近原则

    2. 在同一个作用域中,比如同一个成员方法中,两个变量不能够重名

    3. 属性生命周期较长,伴随对象的创建而创建,伴随着对象销毁而销毁。局部变量生命周期较短,伴随着它的代码块的执行而创建,伴随着代码块的结束而销毁。

    4. 作用范围不同:

      全局变量/属性:可以被本类使用,或其它类使用(通过对象调用)

      局部变量:只能在本类中对应的方法中使用

    5. 修饰符不同

      全局变量/属性可以加修饰符

      局部变量不能加修饰符

构造器

  • 基本语法

    [修饰符] 方法名(形参列表) {

    ? 方法体;

    1. 修饰符可以默认,也可以是其他三种
    2. 构造器没有返回值
    3. 方法名和类名相同
    4. 参数列表和成员方法一样的规则
    5. 构造器的调用由系统完成
public class Constructor {	public static void main(String[] args) {		//我们new一个对象时,直接用构造器指定名字和年龄		Person p1 = new Person("smith", 80);	}}class Person {	String name;	int age;	//构造器	// 1.构造器没有返回值,也不能写void 	// 2.构造器的名称和类Person一样	// 3.(String pName, int pAge)是构造器形参列表,规则和成员方法一样	public Person(String name, int pAge) {		System.out.println("构造器被调用————完成对象的初始化")		name = pName;		age = pAge;	}}
  • 注意事项和使用细节

    public class ConstructorDetail {	public static void main(String[] args) {		Person p1 = new Person("king", 40);		Person p2 = new Person("shaigou");	}}class Person {	String name;	int age;	// 细节1:一个类可以定义多个不同的构造器,即构造器重载	// 第一个构造器	public Person(String pName, int pAge) {		name = pName;		age = pAge;	}	// 第2个构造器	public Person(String pName) {		name = pName;	}	//细节2:构造器名和类名相同	// 细节3:构造器没有返回值	// 细节4:构造器是完成对象的初始化,并不是创建对象	// 细节5:在创建对象是,系统自动调用该类的构造方法		// 细节7:一旦定义了自己的构造器,默认构造器就覆盖了,就不能再使用默认无参构造器	// 除非显式的定义一下,如:Person() {}}class Dog {	// 细节6:如果没有定义构造器,系统会自动給类生成一个默认无参构造器(也叫默认构造器)	// 比如Dog(){},使用javap指令,反编译查看}
    
  • 对象流程分析

    1. 加载Person类信息(Person.class),只会加载一次
    2. 在堆中分配空间(地址)
    3. 完成对象初始化[3.1默认初始化 age = 0 name = null 3.2显式初始化 age=90, name = null, 3.3构造器的初始化 age = 20, name = 小倩]
    4. 将对象在堆中的地址,返回给p(p是对象名,也可以理解为对象的引用)

this

当前对象的属性

  • 注意事项和细节

    public class This {	public static void main(String[] args) {		// 细节1:可以用来访问本类的属性、方法、构造器		// 细节2:用于区分当前类的属性和局部变量		// T t1 = new T();		// t1.f2();	}}class T {	// 细节4:访问构造器:this(参数列表);注意只能在构造器中使用(只能在	// 构造器中访问另一个构造器	// 注意:必须放在第一条语句	public T() {		this("jack",19);		System.out.println("T() 构造器");		// 这里去访问第二种构造器			}	public T(String name, int age) {		System.out.println("第二种 构造器");	}	//细节3:访问成员方法的语句:this.方法名(参数列表)	public void f1() {		System.out.println("f1() 方法");	}	public void f2() {		System.out.println("f2() 方法");		// 调用本类的f1		// 第一种方式		f1();		// 第二种方式		this.f1();	}	// 细节5:this不能在类定义外部使用,只能在类定义的方法中使用}
    

Intellij IDEA

快捷键(ecplise)

  1. 删除当前行:ctrl + D
  2. 复制当前行:ctrl + alt + 向下光标
  3. 补全代码:alt + /
  4. 添加注释:ctrl + /
  5. 导入该行需要的类,先配置auto import,然后使用shift + alt + enter
  6. 快速格式化代码:ctrl + shift + F /ctrl + alt + L
  7. 快速運行程序 shift + F10
  8. 快速生成构造器:alt + insert
  9. 可以查看类的层级(继承)关系: ctrl + h
  10. 将光标放在一个方法上,输入ctrl + b,可以定位到方法
  11. 自动的分配变量名,通过在后面.var

模板

  • 基本语法

    package com.hspedu

  • 包的本质

    包的本质就是创建不同的文件夹/目录来保存类文件

  • 快速入门

  • 包的命名规则:

    只能包含数字、字母、下划线、小圆点,但不能用数字开头,不能是关键字或保留字

  • 命名规范:

    一般是小写字母 + 小圆点

    com.公司名.项目名.业务模块 如:

    com.sina.crm.user //用户模块

  • 常用包

    java.lang.* :默认引用,不用再引用

    java.util.* :系统提供的工具包,工具类,使用Scanner

    java.net.* :网络包,网络开发

    java.awt.* :做java界面开发,GUI

  • 如何引用包

package com.hspedu.pkg;import java.util.Arrays;// 最好需要什么类,就导入那个类中包//import java.util.Scanner; //表示只引入java.util包下的Scanner//import java.util.*; //表示将包下所有类导入public class Import01 {    public static void main(String[] args) {        //使用系统提供的Arrays完成数组排序        int[] arr = {-1, 20 , 12, 30};        //比如对其进行排序        //传统方法是自己编写        //系统提供相关的类,Arrays        Arrays.sort(arr);        //输出排序结果        for (int i = 0; i < arr.length; i++) {            System.out.println(arr[i]);        }    }}
  • 注意事项和使用细节
//细节1:package的作用是声明当前类所在的包,需要放在类的最上面,一个类中最多有一句packagepackage com.hspedu.pkg;//细节2:import指令放在package下面,在类定义之前public class PkgDetail {    public static void main(String[] args) {    }}

访问修饰符

基本介绍

使用注意事项

  1. 修饰符可以用来修饰类中的属性,成员方法

  2. 只有默认的和public才能修饰类,并且遵守以上权限

  3. 成员方法的访问规则和属性一样

封装

封装的理解和好处

  1. 隐藏实现细节
  2. 可以对数据进行验证,保证安全合理

封装实现步骤

  1. 将属性私有化private
  2. 提供一个public set方法,用于对属性判断和赋值
  3. 提供一个public get方法,用于获取属性的值
  • 快速入门

    package com.hspedu.encap;public class Encapsulation01 {    public static void main(String[] args) {        //第一次使用鼠标点击形式运算程序,后面可以用快捷键        Person person = new Person();        person.setName("jack");        person.setAge(20);        person.setSalary(3000);        System.out.println(person.info());    }}class Person {    public String name;    private int age;    private double salary;    public void setAge(int age) {        //判断        if (age >= 1 && age <= 120) {            this.age = age;        } else {            System.out.println("你设置的年龄不对,给出默认年龄18");            this.age = 18;        }    }    public void setName(String name) {        //加入对数据的校验        if (name.length() >= 2 && name.length() <= 6) {            this.name = name;        }else {            System.out.println("名字长度不对");            this.name = "无名人";        }    }    public void setSalary(double salary) {        this.salary = salary;    }    public double getSalary() {        //可以增加对当前对象的权力判断        return salary;    }    public int getAge() {        return age;    }    public String getName() {        return name;    }    public String info() {        return "姓名:" + name + "年龄:" + age + "收入" + salary;    }}
    

继承(代码复用性)

基本语法

class 子类 extends 父类 {

  1. 子类会自动拥有弗雷定义的属性和方法
  2. 父类又叫超类,基类
  3. 子类又叫派生类

细节问题

  1. 子类继承了所有的属性和方法,但是私有属性和方法不能在子类直接访问,要通过公共方法访问

  2. 子类必须调用父类的构造器,完成父类的初始化

  3. 当创建子类对象时,不管使用子类那个构造器,默认情况下总会调用父类无参构造器,如果父类没有提供无参构造器,必须在子类的构造器中用super去指定使用父类哪个构造器完成对父类的初始化工作,否则编译不会通过

  4. 如果希望指定去调用父类的某个构造器,则显示的调用一下

  5. super在使用时,需要放在构造器第一行

  6. super()和this()都只能放在构造器的第一行,因此这两种方法不能共存在一个构造器中

  7. Java所有的类都是Object类

  8. 父类构造器的调用不限于直接父类,将一直往上追溯到Object类

  9. 子类最多只能继承一个父类,即Java中的单继承机制

  10. 不能滥用继承,子类和父类之间必须满足is-a的逻辑关系

super关键字

便利与细节

  1. 调用父类构造器的好处:分工明确,父类属性有父类初始化,子类属性有子类初始化
  2. 当子类中有和父类的成员(属性和方法)重名时,为了访问父类的成员,必须通过super。如果没有重名时,使用super,this,直接访问都是一样的。
  3. super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员;如果多个基类中都有同名的成员,使用super访问遵循就近原则。A->B -> C

super和this的区别

方法重写

?

注意事项和使用细节

  1. 子类的方法的参数,方法名称,要和父类方法的参数,方法名称完全相同
  2. 子类方法的返回类型和父类方法的返回类型一样,或者是父类返回类型的子类,如:父类 返回类型是Object,子类方法返回类型是String
  3. 子类方法不能缩小父类方法的访问权限
package com.hspedu.override_;public class Person {    private String name;    private int age;    public Person() {    }    public Person(String name, int age) {        this.name = name;        this.age = age;    }    public int getAge() {        return age;    }    public String getName() {        return name;    }    public String say() {        return "名字:" + getName() + " 年龄:" + getAge();    }}package com.hspedu.override_;public class Student extends Person {    private String id;    private String score;    public Student() {    }    public Student(String id, String score) {        this.id = id;        this.score = score;    }    public Student(String name, int age, String id, String score) {        super(name, age);        this.id = id;        this.score = score;    }    public String getId() {        return id;    }    public String getScore() {        return score;    }////    public String say() {//////        return "name:" + getName() + " age:" + getAge()//////                + " id:" + getId() + " score:" + getScore();//    }    public String say() {        return super.say()                + " id:" + getId() + " score:" + getScore();    }}package com.hspedu.override_;public class OverrideExercise {    public static void main(String[] args) {        Person person = new Person();        Student student = new Student("傻狗", 10, "0119", "100");        System.out.println(student.say());        System.out.println(person.say());    }}

面向对象编程 - 多态

基本介绍

方法或对象具有多种形态,是面向对象的第三大特征,多态是建立在封装和继承的基础之上

多态的具体体现

  1. 方法的多态

    • 方法的重载

    • 方法的重写

  2. 对象的多态

    (1)一个对象的编译类型和运行类型可以不同

    (2)编译类型在定义对象时,就确定了,不能改变

    (3)运行类型可以变化

    (4) 编译类型看定义时 = 号的左边,运行类型看 = 号的右边

多态注意事项和细节讨论

多态的前提是:两个对象(类)存在继承关系

  1. 多态的向上转型

    1)本质:父类的引用指向了子类的对象

    2)语法:父类编译 引用名 = new 子类类型

    3)特点:编译类型看左边,运行类型看右边。

    ? 可以调用父类中的所有成员(需要遵守访问权限)

    ? 不能调用子类中特有成员

    ? 最终运行效果看子类的具体实现

  2. 多态的向下转型

    1)语法: 子类类型 引用名 = (子类类型) 父类引用

    2) 只能前传父类的引用,不能强转父类的对象

    3)要求父类的引用必须指向的是当前目标类型的对象

    4)可以调用子类类型中所有的成员

  3. 属性没有重写之说,属性的值看编译类型

  4. instanceof 比较符,用于判断对象的运行 类型是否为xx类型或xx类型的子类型

Java的动态绑定机制(非常重要)

  1. 当调用对象方法的时候,该方法和该对象的内存地址/运行类型绑定
  2. 当调用对象属性时,没有动态绑定机制,哪里声明,那里使用

多态的应用

  1. 多态数组:数组的定义为父类类型,里面保存的实际元素类型为子类类型
package com.hspedu.poly_.polyarr;public class Person {    private String name;    private int age;    public Person(String name, int age) {        this.name = name;        this.age = age;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    public String say() {        return "name = " + this.name + "age = " + this.age;    }}package com.hspedu.poly_.polyarr;public class Student extends Person{    private double score;    public Student(String name, int age, double score) {        super(name, age);        this.score = score;    }    public double getScore() {        return score;    }    public void setScore(double score) {        this.score = score;    }    //重写父类的say    @Override    public String say() {        return super.say() + "score = " + score;    }}package com.hspedu.poly_.polyarr;public class Teacher extends Person{    private double salary;    public Teacher(String name, int age, double salary) {        super(name, age);        this.salary = salary;    }    public double getSalary() {        return salary;    }    public void setSalary(double salary) {        this.salary = salary;    }    @Override    public String say() {        return super.say() + "salary = " + salary;    }}package com.hspedu.poly_.polyarr;public class PolyArray {    public static void main(String[] args) {        Person[] persons = new Person[5];        persons[0] = new Person("jack",20);        persons[1] = new Student("jack", 18, 100);        persons[2] = new Student("saith", 19, 30.1);        persons[3] = new Teacher("scott", 30, 20000);        persons[4] = new Teacher("king", 50, 25000);        //循环调用多态数组        for (int i = 0; i < persons.length; i++) {            //编译类型是person,运行类型根据实际情况            System.out.println(persons[i].say());        }    }}
package com.hspedu.poly_.polyarr;public class Person {    private String name;    private int age;    public Person(String name, int age) {        this.name = name;        this.age = age;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    public String say() {        return "name = " + this.name + "age = " + this.age;    }}package com.hspedu.poly_.polyarr;public class Student extends Person{    private double score;    public Student(String name, int age, double score) {        super(name, age);        this.score = score;    }    public double getScore() {        return score;    }    public void setScore(double score) {        this.score = score;    }    //重写父类的say    @Override    public String say() {        return super.say() + "score = " + score;    }    public void study() {        System.out.println("学生 " + getName() + "正在上课");    }}package com.hspedu.poly_.polyarr;public class Teacher extends Person{    private double salary;    public Teacher(String name, int age, double salary) {        super(name, age);        this.salary = salary;    }    public double getSalary() {        return salary;    }    public void setSalary(double salary) {        this.salary = salary;    }    @Override    public String say() {        return super.say() + "salary = " + salary;    }    public void teach() {        System.out.println("老师 " + getName() + "正在上课");    }}package com.hspedu.poly_.polyarr;public class PolyArray {    public static void main(String[] args) {        Person[] persons = new Person[5];        persons[0] = new Person("jack", 20);        persons[1] = new Student("jack", 18, 100);        persons[2] = new Student("saith", 19, 30.1);        persons[3] = new Teacher("scott", 30, 20000);        persons[4] = new Teacher("king", 50, 25000);        //循环调用多态数组        for (int i = 0; i < persons.length; i++) {            //编译类型是person,运行类型根据实际情况            System.out.println(persons[i].say());            if (persons[i] instanceof Student) {                Student student = (Student) persons[i]; //向下转型                student.study();                //  ((Student)persons[i]).study();            } else if (persons[i] instanceof Teacher) {                ((Teacher) persons[i]).teach();            } else {                System.out.println("你的类型有误,请检测");            }        }    }}
  1. 多态参数:方法定义的形参类型为父类类型,实参类型允许为子类类型
package com.hspedu.poly_.polyparamater;public class Employee {    private String name;    private double salary;    public Employee(String name, double salary) {        this.name = name;        this.salary = salary;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public double getSalary() {        return salary;    }    public void setSalary(double salary) {        this.salary = salary;    }    //得到年工资的方法    public double getAnnual() {        return 12 * salary;    }}package com.hspedu.poly_.polyparamater;public class Worker extends Employee{    public Worker(String name, double salary) {        super(name, salary);    }    public void work() {        System.out.println("普通员工 " + getName() + "正在工作");    }    @Override    public double getAnnual() {        return super.getAnnual();    }}package com.hspedu.poly_.polyparamater;public class Manager extends Employee{    private double bonus;    public Manager(String name, double salary, double bonus) {        super(name, salary);        this.bonus = bonus;    }    public double getBonus() {        return bonus;    }    public void setBonus(double bonus) {        this.bonus = bonus;    }    public void manage() {        System.out.println("经理"+ getName() + "正在工作");    }    @Override    public double getAnnual() {        return super.getAnnual() + bonus;    }}package com.hspedu.poly_.polyparamater;public class PolyParamater {    public static void main(String[] args) {        Worker tom = new Worker("tom", 2400);        Manager milan = new Manager("milan", 5000, 2000);        PolyParamater polyParamater = new PolyParamater();        polyParamater.showEmpAnnual(tom);        polyParamater.showEmpAnnual(milan);    }    public void showEmpAnnual(Employee e) {        System.out.println(e.getAnnual()); //动态绑定    }    public void testWork(Employee e) {        if (e instanceof Worker) {            ((Worker)e).work(); //向下转型        } else if (e instanceof Manager) {            ((Manager) e).manage();        } else {            System.out.println("death man");        }    }}

Object类详解

equal方法

== 和equals的对比

  1. == :可以判断基本类型,又可以判断引用类型
  2. == :如果判断基本类型,判断的是值是否相等
  3. == :如果判断引用类型,判断的是地址是否相等,即判断是不是同一个对象
  4. equals:是Object类中的方法,只能判断引用类型
  5. 默认判断的是地址是否相等,子类(String,Integer等)中往往重写该方法,用于判断内容是否相等

hashCode() 方法

  1. 提高具有哈希结构的效率

  2. 两个引用,如果指向是同一个对象,则哈希值是相同的

  3. 两个引用,如果指向是不同对象,则哈希值是不同的

  4. 哈希值主要是根据地址号来的,不能完全将哈希值等价于地址

    package com.hspedu.hashcode;import com.hspedu.modifier.A;public class HashCode_ {    public static void main(String[] args) {        A aa = new A();        A aa2 = new A();        A aa3 = aa;        System.out.println("aa.hashcode(): " + aa.hashCode());        System.out.println("aa2.hashcode(): " + aa2.hashCode());        System.out.println("aa3.hashcode(): " + aa3.hashCode());    }}
    

toString方法

基本介绍

默认返回:全类名 + @ + 哈希值的十六进制,【查看Object的toString方法】,子类往往重写toString方法,用于返回对象的属性信息

当直接输出一个对象时,toString方法会被默认的调用,比如System.out.println(monster),默认调用toString()方法

package com.hspedu.hashcode;public class ToString_ {    public static void main(String[] args) {        /*        Object的toString()源码        //getClass().getName()类的全类名(包名+类名)        //Integer.toHexString(hashCode()) 将对象hashCode值转成16进制字符        public String toString() {        return getClass().getName() + "@" + Integer.toHexString(hashCode());    }         */        Monster monster = new Monster("妖怪", "巡山", 1000);        System.out.println(monster.toString() + "hashcode:" + monster.hashCode());        System.out.println("===当直接输出一个对象时,toStirng方法会默认被调用===");        System.out.println(monster);    }}class Monster {    private String name;    private String job;    private double sal;    public Monster(String name, String job, double sal) {        this.name = name;        this.job = job;        this.sal = sal;    }    //重写toString方法,处处对象的属性    //使用快捷键即可alt + insert -> toString    @Override    public String toString() { //重写后一般是吧对象的属性值输出        return "ToString_{" +                "name='" + name + '\'' +                ", job='" + job + '\'' +                ", sal=" + sal +                '}';    }}

finalize()方法

  1. 当对象被回收时,系统自动调用该对象的finalize方法。子类可以重写该方法做一些释放资源的操作
  2. 什么时候回收:当某个对象没有任何引用时,jvm就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁该对象,在销毁对象前,调用finalize方法
  3. 垃圾回收机制的调用,是由系统决定的,也可以通过System.gc()主动触发垃圾回收机制
package com.hspedu.hashcode;public class Finalize {    public static void main(String[] args) {        Car car = new Car("宝马");        car = null; //这时car对象就是一个垃圾,垃圾回收器就会回收对象,        //在销毁对象前,会调用finalize方法程序员可以在finalize中,        //写自己的业务逻辑代码,如:释放资源,数据库连接,或者打开文件        //如果补充些finalize,那么就会调用Object类的finalize,即默认处理        System.gc();//主动调用垃圾回收器 可能会成功        System.out.println("程序退出、、、、");    }}class Car {    private String name;    public Car(String name) {        this.name = name;    }    //重写finalize    @Override    protected void finalize() throws Throwable {        System.out.println("我们销毁汽车" + name);        System.out.println("释放了一些资源");    }}

断点调试

提示:在断点调试中,是运行状态,是以对象的运行类型来执行的。

快捷键

F5:跳入方法内

F6:逐行执行代码

shift + F7:跳出方法

F8:resume,执行到下一个断点

package com.hspedu.smallchange.oop;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Scanner;/** * 该类时完成零钱通的各个功能的类 * 使用oop(面向对象编程) * 将各个功能对应一个方法 */public class SmallChangeOOP {    //属性    //定义相关变量    boolean loop = true;    Scanner scanner = new Scanner(System.in);    String key = "";    //2.完成零钱通明细    //(1)可以把收益入账和消费,保存到数组(2)可以使用对象(3)可以使用String拼接    String details = "---------零钱通明细----------";    //3.完成收益入账 完成功能驱动程序员增加新的变化和代码    double money = 0;    double balance = 0;    Date date = null;   //date是java.util.Date类型,表示日期    SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd HH:mm"); //可以用于日期格式化    //4.消费    //定义消费的原因    String note = "";    //先完成显示菜单,并可以选择    public void mainMenu() {        do {            System.out.println("\n=======零钱通菜单========");            System.out.println("\t\t\t1 零钱通菜单");            System.out.println("\t\t\t2 收益入账");            System.out.println("\t\t\t3 消费");            System.out.println("\t\t\t4 退出");            System.out.println("请选择(1-4)");            key = scanner.next();            //使用switch分支控制            switch (key) {                case "1" :                    this.detail();                    break;                case "2" :                    this.income();                    break;                case "3" :                    this.pay();                    break;                case "4" :                    this.exit();                    break;                default:                    System.out.println("选择有误,请重新选择");            }        }while (loop);    }    //完成零钱通明细    public void detail() {        System.out.println(details);    }    //完成收益入账    public void income() {        System.out.print("收益入账金额");        money = scanner.nextDouble();        //money的值范围应该校验        //思路:找出不正确的金额条件,然后给出提示,就直接break//                    if(money <= 0) {//                        System.out.println("收益入账金额需要大于0");//                        break;//                    }        //找出正确金额的条件        if(money > 0) {            balance += money;            //拼接收益入账信息到details            date = new Date(); //获取当前日期            details += "\n收益入账\t" + money + "\t" + sdf.format(date) + "\t" + balance;        } else {            System.out.println("收益入账金额要大于0");            return;        }        return;    }    //完成消费    public void pay() {        System.out.print("消费金额:");        money = scanner.nextDouble();        //money的值范围要校正        //找出金额不正确的情况        if (money <= 0 || money > balance) {            System.out.println("你的消费金额应该在 0-" + balance);            return;        }        System.out.print("消费说明:");        note = scanner.next();        balance -= money;        date = new Date(); //获取当前信息        details +="\n" + note + "\t\t-" + money + "\t" + sdf.format(date) + "\t" + balance;        return;    }    //退出    public void exit() {        //(1)定义一个变量choice,接收用户的输入        //(2)使用while + break,来处理接收到的输入        //(3)退出while后,再判断choice是y还是n,就可以决定是否退出        //(4)建议一段代码只实现一个小功能,尽量不要混在一起        String choice = "";        while (true) {            System.out.println("你确定要退出吗? y/n");            choice = scanner.next();            if ("y".equals(choice) || "n".equals(choice)){                break;            }        }        //当用户退出while,进行判断        if (choice.equals("y")) {            loop = false;        }        return;    }}package com.hspedu.smallchange.oop;import com.hspedu.smallchange.SmallChangeSys;/** * 这里我们直接调用SmallChangeSysOOP对象,显示主菜单即可 */public class SmallChangeSysApp {    public static void main(String[] args) {        new SmallChangeOOP().mainMenu();    }}

类变量和类方法

定义语法

访问修饰符 static 数据类型 变量名;

static 访问修饰符 数据类型 变量名;

访问方法

类名.类变量名

对象名.类变量名【静态变量的访问修饰符的访问权限和范围和普通属性是一样的】

类变量使用注意事项和细节讨论

  1. 什么时候需要用类变量

    当我们要让某个类的所有对象都共享一个变量时,就可以考虑使用类变量(静态变量),如:定义学生类,统计所有学生共交多少钱

  2. 类变量与实例变量(普通属性)区别

    类变量是该类的所有对象共享的,而实例变量是每个对象共享的

  3. 加上static称为类变量或静态变量,否则称为实例变量/普通变量/非静态变量

  4. 类变量可通过 类名.类变量名 或者 对象名.类变量名 来访问,但Java设计者推荐我们使用 类名.类变量名方式访问

  5. 实例变量不能通过 类名.类变量名 访问

  6. 类变量是类加载时就初始化了,也就是说,即使没有创建对象,只要类加载,就可以使用类变量

  7. 类变量的生命周期是随类的加载开始,随着类消亡而销毁

类方法基本介绍

访问修饰符 static 数据返回类型 方法名(){}

static 访问修饰符 数据返回类型 方法名(){}

类方法的调用

使用方式:类名.类方法名 或者 对象名.类方法名 【前提是满足访问修饰符的权限和范围】

类方法使用的注意事项和细节讨论

  1. 类方法和普通方法都是随着类的加载而加载,将结构信息存储在方法区

    类方法中无this的参数

    普通方法中隐含this的参数

  2. 类方法可以通过类名调用,也可以通过对象名调用

  3. 普通方法和对象有关,需要通过对象名调用,比如对象名.方法名(参数),不能通过类名调用

  4. 类方法中不允许使用和对象有关的关键字,比如this和super。普通方法(成员方法)可以

  5. 类方法(静态方法)中只能访问 静态变量或静态方法。

  6. 普通成员方法,既可以访问 普通方法(方法),也可以访问静态成员和非静态成员(必须遵守访问权限)

理解mian方法语法

  1. java虚拟机需要调用类的main()方法,所以该方法的访问权限必须是public
  2. java虚拟机在执行main()方法是不必创建对象,所以该方法必须是static
  3. 该方法接收String类型的数组参数,该数组中保存执行java命令时传递给所运行的类的参数
  4. java执行的程序 参数1 参数2 参数3

特别提示:

  1. 静态方法main可以访问本类的静态方法
  2. 静态方法main不能访问本类的非静态方法

代码块

基本语法

[修饰符] {

? 代码;

};

说明:

  1. 修饰符可选,要写的话,只能写static
  2. 代码块分为两类,使用static修饰的叫静态代码块,没有static修饰的,叫普通/非静态代码块
  3. 逻辑语句可以为任何逻辑语句
  4. ;可以写,也可以省略
package com.hspedu.codeblock_;

public class CodeBlock {
    public static void main(String[] args) {
        new Movie("哈");
        Movie("姆", 120)
    }
}

class Movie {
    private String name;
    private double price;
    private String director;

    //下面三个构造器中有相同的语句
    //可以把相同的语句放到一个代码块中
    //不管调用哪个构造器,创建对象,都会先调用代码块内容
    //代码块调用顺序先与构造器
    {
        System.out.println("广告结束");
        System.out.println("电影结束");
    }
    public Movie(String name) {
        this.name = name;
    }

    public Movie(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public Movie(String name, double price, String director) {
        this.name = name;
        this.price = price;
        this.director = director;
    }
}

注意事项和细节讨论

  1. static代码块叫做静态代码块,作用是对类进行初始化,并且随着类的加载而执行,并且只会执行一次。而普通代码块,每创建一个对象,就执行

  2. 类什么时候被加载

    • 创建子类对象实例时

    • 创建子类对象实例,父类也会被加载,而且父类先被加载,子类后被加载

    • 使用类的静态成员(静态属性,静态方法)

  3. 普通代码块,在创建对象实例时,会被隐式调用。被创建一次,就会被调用一次。如果只使用类的静态成员时,普通代码块不会被执行。

  4. 创建一个对象时,在一个类调用顺序是:

    • 调用静态代码块和静态属性初始化(注意:静态代码块和静态属性初始化调用的优先级一样,如果有多个静态代码块和多尔静态变量初始化,则按他们定义的顺序调用)

以上内容通过韩顺平老师的视频做的笔记
https://space.bilibili.com/651245581?from=search&seid=11092504021297742460&spm_id_from=333.337.0.0