此文章是来源于尚硅谷宋红康java教学总结写的笔记,适于入门新手,建议一遍看视频,一边自己写,本文章作为参考
目录
语言概述与基础语法
java简介
1.JDK(java软件开发工具箱),JRE(java运行时环境),JVM(java虚拟机)三者之间的关系,以及JDK,JRE包含的主要结构有哪些?
JDK = JRE + Java的开发工具(javac.exe,java.exe,javadoc.exe) ,JRE= JVM + API(java核心类库)
2.为什么要配置path环境变量?如何配置?
答:希望java开发工具在任何路径下都可以执行。
3.原码、反码、补码
原码:进制数据的二进制表现形式就是原码,原码最左边的一个数字就是符号位,0为正,1为负
反码:反码的存在是为了正确计算负数,因为原码不能用于计算负数
补码:因为反码不能解决负数跨零(类似于-6 + 7)的问题,所以补码出现了
在计算机当中都是使用补码来进行计算和存储的
正数原码符号位(最左边位)为0,负数符号位为1对于正数三码合一,对于负数的反码:符号位不变原码求反
负数的补码:负数的反码加1 二进制存储方式:计算机的底层都以补码的方式来存储数据!所有数字在计算机底层都以二进制的形式存在
4.编写:将 编写的java代码保存在以“.java”结尾的源文件中
编译:使用javac.exe命令编译我们的java源文件。 格式: javac 源文件.java 运行:使用java.exe命令解释运行我们的字节码文件。 格式:java 源文件
转义字符与占位符
转义字符:
实战代码:
public class test_17 {
public static void main(String[] args) {
System.out.println("\''你好\''"); //''你好''
System.out.println("你好\n啊"); //你好 下行啊
System.out.println("你好\\啊"); //你好\啊
System.out.println("你好\t啊");//你好 啊
}
}
占位符:
实战代码:
public class test_17 {
public static void main(String[] args) {
String str=null;
str=String.format("Hi,%s", "王力"); // Hi,王力
System.out.println(str);
str=String.format("Hi,%s:%s.%s", "王南","王力","王张"); // Hi,王南:王力.王张
System.out.println(str);
System.out.printf("字母a的大写是:%c %n", 'A'); //字母a的大写是:A
System.out.printf("3>7的结果是:%b %n", 3>7); //3>7的结果是:false
System.out.printf("100的一半是:%d %n", 100/2); //100的一半是:50
System.out.printf("100的16进制数是:%x %n", 100); // 100的16进制数是:64
System.out.printf("100的8进制数是:%o %n", 100); // 100的8进制数是:144
System.out.printf("50元的书打8.5折扣是:%f 元%n", 50*0.85); // 50元的书打8.5折扣是:42.500000 元
System.out.printf("上面价格的16进制数是:%a %n", 50*0.85); // 上面价格的16进制数是:0x1.54p5
System.out.printf("上面价格的指数表示:%e %n", 50*0.85); // 上面价格的指数表示:4.250000e+01
System.out.printf("上面价格的指数和浮点数结果的长度较短的是:%g %n", 50*0.85);// 上面价格的指数和浮点数结果的长度较短的是:42.5000
System.out.printf("上面的折扣是%d%% %n", 85); //上面的折扣是85%
System.out.printf("字母A的散列码是:%h %n", 'A'); //字母A的散列码是:41
}
}
整理转载与 java中String的格式化format()方法_不宅的阿瑞的博客-CSDN博客_java stringformat
运算符优先级
输入与输出
输入
如何从键盘获取不同类型的变量:需要使用Scanner类
具体实现步骤:
1.导包:import java.util.Scanner;
2.Scanner的实例化:Scanner scan = new Scanner(System.in);
3.调用Scanner类的相关方法,来获取指定类型的变量
注意:
需要根据相应的方法,来输入指定的类型,如果输入的数据类型与要求的类型不匹配时,会报异常.InputMismatchException类型不匹配
import java.util.Scanner;
class ScannerText{
public static void main(String[] args){
Scanner scan = new Scanner(System.in);
System.out.println("请输入你的名字:");
String name = scan.next();
System.out.println(name);
System.out.println("请输入你的芳龄:");
int num = scan.nextInt();
System.out.println(num);
System.out.println("请输入你的体重:");
double weight = scan.nextDouble();
System.out.println(weight);
System.out.println("你是否相中了我?(true/false)");
boolean islove = scan.nextBoolean();
System.out.println(islove);
//对于char类型的获取,Scanner没有提供相应的方法。只能获取一个字符串
System.out.println("请输入你的性别:(男/女)");
String gender = scan.next();//男
char genderChar = gender.charAt(0);//获取索引为0的位置上的字符
System.out.println(genderChar);
}
}
输出
代码:输出x为6位,空白用0补充。y输出保留两位小数
int x = 100;
double y = 231.445546;
System.out.printf("x=%06d,y=%.2f",x,y); //x=000100,y=231.45
标识符的使用
标识符:
凡是自己可以起名字的地方都叫标识符。 比如:类名,变量名,方法名,接口名,包名...
标识符的命名规则:
> 由26个英文字母大小写,0-9,_或$组成
> 数字不可以开头
> 不可以使用关键字和保留字,但能包含关键字保留字。
> java中严格区分大小写,长度无限制。
> 标识符不能包含空格
java的名称命名规范:
> 包名:多单词组成时所有字母都小写:xxxyyy
> 类名、接口名:多单词组成时所有单词的首字母大写:XxxYyyZzz
> 变量名、方法名:多单词组成时,第一个单词首字母小写,第二单词开始首字母大写:xxxYyyZzz
> 常量名:所有字母都大写,多单词时每个单词用下划线连接:XXX_YYY_ZZZ
数据类型
一、变量按数据类型来分:
基本数据类型: 整数:byte \ short \ int \ long 浮点型:float \ double 字符型:char 布尔型:boolean
引用数据类型; 类:(class) 接口:(interface) 数组:(array)、 String
二、变量在声明中的位置: 成员变量 VS 局部变量
1.整数:byte(1字节=8bit) \ short(2字节) \ int(4字节) // (1) `byte范围;-128 ~ 127
byte b1 = 12;
byte b2 = -128;
//b2 = 128; 编译不通过
System.out.println(b1);
System.out.println(b2);
(1)声明Long行变量,必须以"l"或"L"结尾 (2)通常,定义整形变量时,使用int型。
short s1 = 128;
int i1 = 1234;
long l1 = 1354556l;
System.out.println(l1);
2.浮点型:float(四字节) \ double(八字节) (1)浮点型,表示带小数点的数值 (2)float表示的范围比Long还大,精度不高
double d1 = 123.3;
System.out.println(d1+1);
(3)定义float类型变量时,变量要以“f”或"F"结尾 float f1 = 12.3f; System.out.println(f1); // 通常定义浮点型用"double"
//3.浮点型:Char(1字符等于2字节)
//(1)定义char型变量,通常用一对'',内部只写一个字符
char c1 = 'a';
System.out.println(c1);
//(2)表示方法:1.声明一个字符。2.转义一个字符
char c5 = '\n';//换行符
c5 = '\t';//制表符
System.out.print("hello" + c5);
System.out.println("world");
数据类型转换
基本数据之间的运算规则: 前提:这里只是7种基本数据类型变量间的运算,不包含boolean类型的。
自动类型的提升
结论:当容量小的数据类型的变量与容量大的数据类型的变量运算时,结果自动提升为容量大的数据类型。 byte、char、short——int—— long—— float—— double 特别的,当byte、char、short三种数据类型的变量做运算时,结果为int型
说明:此时容量大小指的是,表示数的范围的大和小,比如:float的容量大于long的容量
强制类转换:
自动提升运算的逆运算。
(1)需要使用强转符:() (2)注意点:强制类转换可能导致精度损失。 强制类转换:自动提升运算的逆运算。 1.需要使用强转符:() 2.注意点:强制类转换可能导致精度损失
double d1 = 12.9;
// 精度损失举例1
int i1 = (int)d1;//裁区操作
System.out.println(i1);
//没有精度损失
long l1 = 123;
short s2 = (short)l1;
System.out.println(l1);
//精度损失举例2
int i2 = 128;
byte b = (byte)i2;
System.out.println(b);//-128
3.String类型变量的使用 :(1)String属于引用数据类型 (2)声明Sting变量时,要使用一对"" (3)string可以和8种基本数据类型做运算,且运算只能是连续运算:+ (4)运算结果仍然是string类型
特别注意:
char a = 'a';
int b = 10;
string c = "hello"
system.out.println(a + b + c) //107hello 这里数据类型自动提升
逻辑运算符与位运算符
逻辑运算符 &(逻辑与) &&(短路与) 一假则假, 相同点:1.& 与 && 运算结果相同 2.当符号左边为True时,两者都会执行符号右边的运算 不同点:当符号左边为False时,&继续执行符号右边的运算,&&不会执行符号右边的运算
| (逻辑或) ||(短路或) 一真则真,
相同点:1.| 与 || 运算结果相同 2.当符号左边为False时,两者都会执行符号右边的运算 不同点:当符号左边为True时,|继续执行符号右边的运算,||不会执行符号右边的运算 !(逻辑非) 取反 ^ (逻辑异或) 相同为True,不同为False
位运算符
1.位运算符操作的都是整型的数据
2.<< : 在一定范围内,每向左移一位,相当于*2
>> : 在一定范围内,每向右移一位,相当于/2(负数最高位拿1补)
: 无符号右移,被移位二进制最高位无论是0或者1,空缺位都拿0补
& | ^ ! : 二进制0相当于Flase,1相当于True,按逻辑中的运算符一样运算
三元运算符
三元运算符 1.结构:(条件表达式)? 表达式1 :表达式2
2.说明:
(1)条件表达式的结果为boolean类型
(2)根据条件表达式的真或假,决定执行表达式1,还是表达式2 如果表达式为ture,则执 行表达式1 如果表达式为false,则执行表达式2
(3)表达式1和表达式2要求是一致的
3.凡是可以使用三元运算符的地方,都可以改写成if-else!
4.如果程序即可以使用三元运算符又可以使用if-else,那么优先使用三元运算符,原因:简洁、执行效率高
实例求两位数大小:
Scanner scan = new Scanner(System.in);
int i = scan.nextInt();
int j = scan.nextInt();
String maxStr = (i > j) ? "i大" : ((i == j) ? "相等" : "j大");
System.out.println(maxStr);
求三位数中最大的数:
Scanner scan = new Scanner(System.in);
int i = scan.nextInt();
int j = scan.nextInt();
int z = scan.nextInt();
int maxValue = ((i > j)?i:j)> z ? ((i > j)?i:j) : z
++i 与 i++
++i:前缀递增的意思,++i是先进行自增或者自减运算,再进行表达式运算。 i++: 后缀递增的意思,i++是先进行表达式运算,再进行自增运算。
配合逻辑运算符实例:
class LianXi {
public static void main(String[] args) {
int x = 1;
int y = 1;
if(x++ == 2 & ++y ==2){
x = 7;
}
System.out.println("x=" + x + "y=" + y); //x = 2 y =2
int x1 = 1;
int y1 = 1;
if(x1++ == 2 && ++y1 ==2){
x1 = 7;
}
System.out.println("x1=" + x1 + "y1=" + y1);// x1 = 2 y1 = 1
int b1 = 2;
++b1;
System.out.println(b1);
}
}
特别的,这里括号没用
int i = 10;
int j = (i++);
System.out.println("i = " + i + " j = " + j); //i = 11 j = 10
switch选择语句用法
switch 语句遵从规则:
①表达式必须计算出一个 char 、byte、short、int、string 类型等数据,并且它必须用括号括住。
②值1,...,值N 必须与表达式的值具有相同的数据类型,当表达式的值与 case 语句的值相匹配时,执行该 case语句中的语句(每个 case 语句都顺序执行)
③ 关键字break是可选的,break 语句终止整个 switch 语句。若 break 语句不存在,下一个case 语句将被执行。
④ 默认情况(default)是可选的,它用来指定情况都不为真时的操作,默认情况总是出现在switch 语句块的最后。
switch语句格式:
witch(表达式){
case 表达式常量1:
语句1; [ break;] // [ ] 表示可选
case 表达式常量2:
语句2; [ break;]
......
case 表达式常量n:
语句n;
[ break;]
[default:语句n+1;]
}
For循环
For循环结构的使用
一、循环结构的四个要素
(1)初始条件 (2)循环条件 (3)循环体 (4)迭代条件
二、For循环的结构
for((1);(2);(4)){
(3)
}
执行过程:(1)-(2)-(3)-(4)-(2)-(3)-(4)...(2)
class ForText{
public static void main(String[] args){
for (int i = 1;i <= 5;i++ ){
System.out.println("520");
}
//System.out.println(i);
//练习1
int i = 1;
for(System.out.print('a');i <= 3;System.out.print('b'),i++){
System.out.print('c');//输出结果 acbcbcb
}
//练习2、输出1-100的偶数,偶数和,一共多少偶数
int sum = 0;
int count = 0;
for(int j = 1;j <= 100;j++){
if (j % 2 == 0){
sum += j;
count++;
System.out.println(j);
}
}
System.out.println("1-100的偶数和为:" + sum);
System.out.println("1-100的偶数个数为:" + count);
for(int b = 1;b <= 150;b++){
System.out.print(b + " ");
if(b % 3 == 0){
System.out.print("foo ");
}if (b % 5 == 0){
System.out.print("biz ");
}if (b % 7 == 0){
System.out.print("baz ");
}
System.out.println();
}
}
}
do-while循环
一、循环结构的四个要素
(1)初始条件 (2)循环条件 (3)循环体 (4)迭代条件
二、do-while循环的结构
① do{
③;
④; }
while(②);
执行过程:(1)-(3)-(4)-(2)-(3)-(4)...(2)
do-while至少会执行一次循环体
int i = 10;
do{
System.out.println(i);
i--;
}
while(i < 10);
结果:10
break与continue
break和continue都可在循环语句里面使用,也都可以控制外层的循环。但是continue只能在循环语句里面使用,break也可以使用在switch语句里面。 break具体作用在循环语句中的具体作用是,跳出当前循环,当然还可以跳出所有的循环。当前循环中break语句之后的语句都不会执行。
控制外层循环实例
public class Test {
public static void main(String[] args) {
go : for (int j = 0; j < 5; j++) {//外层循环别名为go
//循环打印1,2,3,4
for (int i = 0; i < 5; i++) {
if (i == 1) {//当i等于1的时候
break go;//跳出外层循环,直接break只跳出内循环
}
System.out.println(i);
}
}
}
}//输出结果:0
数组
一维数组
一、数组的概论
1.数组的理解(Array),是多个相同类型按一定顺序排列的集合,并使用一个名字命名
并通过编号的方式对这些数据进行统一管理
2.数组的概念
数组名
元素
角标、下标、索引
数组的长度,元素的个数
3.数组的特点:
1)数组是有序排列的
2)数组属于引用数据类型的变量。数组的元素。既可以是基本的数据类型,也可以是引用 数据类型
3)创建的组对象会在内存中开辟一整块连续的空间
4)数组的长度一旦确定,就不能的修改
4.数组的分类:
1)按照维数,一维数组、二维数组
2)按照数组元素的类型,基本数据类型元素的数组、引用数据类型元素的数组
public class Array1Text1 {
public static void main(String[] args) {
// 一维数组的声明和初始化
int num;// 声明
num = 10;// 初始化
int id = 1001;// 声明 + 初始化
int[] ids;// 声明
// 1.1静态初始化:数组的初始化和数组的元素的赋值操作同时进行
ids = new int[] { 1001, 1002, 1003, 1004 };
// 1.2动态初始化:数组的初始化和数组元素的赋值操作同时进行
String[] names = new String[5];
System.out.println(names[0]);//null
// 总结:一旦初始化完成,其长度就确定了
// 2.如何调用数组的指定的元素:通过角标的方式调用。
// 数组的角标(或索引)从0开始的,当数组的长度-1结束
names[0] = "张三";
names[1] = "张四";
names[2] = "张无";
names[3] = "张六";
names[4] = "张七";
// 3.获取数组的长度
// 属性:length
System.out.println(names.length);// 5
System.out.println(ids.length);// 4
// 4.如何遍历数组
for (int i = 0; i < names.length; i++) {
System.out.println(names[i]);
}
for (int i = 1; i < ids.length; i++) {
System.out.println(ids[i]);
}
内存解析
二维数组
对于二维数组的理解,我们可以看成是一维数组array1又作为宁一个一维数组array2的元素的存在,其实,从数组的底层运行机制来看,其实没有多维数组。
二维数组的声明和初始化
public class Array2Text {
public static void main(String[] args) {
//静态初始化
int[][] arr = new int[][] {{1,2,3},{4,5},{6,7,8}};
//动态初始化1
String[][] arr1 = new String[2][3];
//动态初始化2
String[][] arr2 = new String[3][];
//也是正确的写法
int[] arr3[] = new int[][] {{1,2,3},{4,5},{6,7,8}};
int[] arr4[] = {{1,2,3},{4,5},{6,7,8}};
//如何调用数组元素的位置
System.out.println(arr[0][1]);//2
System.out.println(arr1[1][1]);//null
//System.out.println(arr2[1][0]);//报错,空指针问题
arr2[1] = new String[4];//给第二行创建一个长度为4的数组
arr2[1][0] = "zhangsan";
System.out.println(arr2[1][0]);
//获取数组的长度
System.out.println(arr3.length);//3
System.out.println(arr3[0].length);//3
System.out.println(arr3[1].length);//2
//如何遍历二维数组
for(int i = 0;i < arr3.length;i++) {
for(int j = 0;j < arr3[i].length;j++) {
System.out.print(arr3[i][j]);
}
System.out.println();
}
二维数组的使用:
规定:二维数组分为外层数组的元素,内层数组的元素使用
int arr = new int4;
外层元素:arr[0],arr[1]等
数组元素的初始化值为
针对于初始化方式一:比如:int arr = new int[4];
外层元素的初始值为:地址值
内层元素的初始值为:与一维数组的初始值情况相同
针对与初始化方式二:比如:int arr = new int[4];
外层元素的初始化值为:null
内层元素的初始化值为:不能调用,否则报错(空指针)
int[][] arr = new int[4][3];
System.out.println(arr[0]);//[I@15db9742
System.out.println(arr[0][0]); //0
//System.out.println(arr);//[[I@6d06d69c
System.out.println("*****************");
float[][] arr1 = new float[4][3];
System.out.println(arr1[0]);//地址值
System.out.println(arr1[0][0]);//O.O
System.out.println("*****************");
String[][] arr2 = new String[4][2];
System.out.println(arr2[0]);//[Ljava.lang.String;@7852e922
System.out.println(arr2[0][0]);//null
int[][] arr3 = new int[4][];
System.out.println(arr3[0]); //null
//System.out.println(arr3[0][1]);// 报错,空指针
内存解析
杨辉三角
package com.atguigu.contacts;
public class YangHuiText1 {
public static void main(String[] args) {
int[][] arr = new int[10][];//创建二维数组的行
for(int i = 0;i < arr.length;i++) {
arr[i] = new int[i+1];
}
for(int i = 0;i < arr.length;i++) {
for(int j = 0;j < arr[i].length;j++) {
if((j == 0) || (j == i)) {
arr[i][j] = 1;
}else {
arr[i][j] = arr[i-1][j] + arr[i-1][j-1];
}
}
}
for(int i = 0;i < arr.length;i++) {
for(int j = 0;j < arr[i].length;j++) {
System.out.print(arr[i][j] + " ");
}
System.out.println();
}
}
}
冒泡排序法
package com.atguigu.exer;
//冒泡排序法
public class BubbleSortText {
public static void main(String[] args) {
int[] arr = new int[] {34,23,56,-43,67,90,12,-50,99};
for(int i = 0;i < arr.length - 1;i++) {
for(int j = 0;j < arr.length - i -1;j++) {
if(arr[j] > arr[j+1]) {
int temp = arr[j+1];
arr[j+1] = arr[j];
arr[j] = temp;
}
}
}
for(int i = 0;i < arr.length;i++) {
System.out.print(arr[i] + " ");
}
}
}
二分法查找
二分法查找 前提所有查找的数组必须有序
public class ArrayReRenFa {
public static void main(String[] args) {
int[] arr = new int[] { -98, -34, 2, 34, 54, 66, 79, 105, 210, 333 };
int dest = 79;
boolean isflag = true;
int head = 0;
int tail = arr.length - 1;
while(head <= tail) {
int middle = (head + tail)/2;
if(dest == arr[middle]) {
System.out.println("找到了指定的元素,索引位置在:" + middle);
isflag = false;
break;
}else if(dest < arr[middle]) {
tail = middle -1;
}else {
head = middle + 1;
}
}
if(isflag) {
System.out.println("没有找到指定元素");
}
}
}
数组综合
public class ArrayText {
public static void main(String[] args) {
//对数组的创建,复制、赋值、最大值、最小值、总和、平均值、反转
//排序、查找的总体练习
int[] arr = new int[] {23,43,234,65,423,546,32,11,45,-65,-56,0};
int[] arr1 = new int[6];
int[][] arr2 = new int[][] {{12,23,43},{23,54,65},{54,36,34,23}};
int[][] arr3= new int[3][];
arr3[1] = new int[3];
System.out.println(arr1);//[I@15db9742
System.out.println(arr2[2][2]);//34
System.out.println(arr3);//[[I@6d06d69c
System.out.println(arr3[0]);//null
System.out.println(arr3[1]);//[I@7852e922
System.out.println(arr3[1][2]);//0
//****************************
//遍历赋值
Scanner scan = new Scanner(System.in);
for(int i = 0;i < arr1.length;i++) {
arr1[i] = scan.nextInt();
}
//****************************
//打印数组
//法一,遍历
for(int i = 0;i < arr1.length;i++) {
System.out.print("[" + arr1[i] + "]" + "\t");
}
System.out.println();
//法二,调用Arrays.toString类
System.out.println(Arrays.toString(arr1));
求最大值、最小值、总和、平均值
//法一,调用Arrays.stream(arr).min.getAsInt();
int min = Arrays.stream(arr).min().getAsInt();
int max = Arrays.stream(arr).max().getAsInt();
int sum = Arrays.stream(arr).sum();
double avarege = sum / arr.length;
System.out.println("最小值为:" + min + "最大值为:" + max);
System.out.println("最总值为:" + sum + "最平均值为:" + avarege);
//法二,遍历取个临时值temp,演示max
int sum1 = arr[0];
for(int i = 0;i < arr.length;i++) {
if(sum1 < arr[i]) {
sum1 = arr[i];
}
}
System.out.println(sum1);
反转
int temp;
for(int i = 0,j = arr.length - i -1;i < j;i++,j--) {
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
System.out.println(Arrays.toString(arr));
Arrys函数的使用
1.数组排序:
Arrays.sort()
2.Arrays.binarySearch():找到定位数组的下标:
3.Arrays.toString():数组的打印。
4.Arrays.fill 数组的填充
5.Arrays.equals 判断两个数组大小是否相等。
6.Arrays.asList(a) 查看数组中的特定值。
该方法是将数组转化为list。
(1)该方法不适用于基本数据类型(byte,short,int,long,float,double,boolean)
(2)该方法将数组与列表链接起来,当更新其中之一时,另一个自动更新
(3)不支持add和remove方法 (4)其最终结果只可能是true和false。
特别的:random范围为[0,1),想取指定范围[a,b]时,指定公式有random()*(b-a+1)+a
//数组的常见异常: /1.数组角标的异常:ArrayIndexOutOfBoundsExcetion 2.空指针异常:NullPointerException/
eclipse常用快捷键
1、补全代码:alt + /
2、快速修复:ctrl + 1
3、批量导包:ctrl + shift + o
4、单行注释:ctrl + /
5、多行注释:ctrl + shift + /
6、取消多行注释:ctrl + shift + \
7、复制多行代码:ctrl + alt + down
8、删除指定行代码:ctrl + d
9、上下移动代码:alt + up alt + down
10、 在下一行添加代码:shift + enter
11、在上一行添加代码:ctrl + shift + enter
12、查看源码:ctrl + 选中指定结构 或 ctrl + shift + t
13、退回上一个/下一个查看的页面:alt + left alt + right
14、查看类的继承树:ctrl + t
15、格式化代码:ctrl + shift + f
16、选中数行整体后移/前移:tab shift + tab
17、查看类结构并搜索方法:ctrl + o
18、批量修改变量名方法名:alt + shift + r
19、大小写切换 变大写:ctrl + shift + x 变小写:ctrl + shift + y
20、查找与替换:ctrl + f
面对对象(初)
面向对象主要知识
1.java类及类的成员:属性、方法、构造器、代码块、内部类
2.三大特征:封装、继承、多态
3、其他关键字:this、super、static、final、abstract、interface、package、import
理解"万事万物皆对象
1.在java语言规范中,我们都将功能、结构封装到类中,通过类的实例化,来调用具体的 功能结构,如:
Scanner,String等
文件,file
网路资源,URL
2.涉及java语言与前端Html,后端的数据库交互时,前后端的结构在java层面交互时,都 体现为类、对象
面对过程与面对对象
面向过程:强调的是功能行为,以函数为最小单位,考虑怎么做。
面向对象:强调具备了功能的对象,以类/对象为最小单位。
类(class): 是对一事物的描述,是抽象的,概念上的定义
对象:(object):是实际存在的该类事物的每个个体,因而也成为实例,对象是类派生出来的。
一、设计类其实就是设计类的成员
属性=成员变量=field= 域、字段
方法=成员方法=函数=method
创建类的对象=类的实例化=实例化类
二、类和对象的使用(面对对象落地的实现)
1.创建类、设计类的成员
2.创建类的对象
3.通过"对象.属性"或"对象.方法"调用对象的结构
三、如果创建了一个类的多个对象,则每个对象都独立的拥有一套类的属性。(非static的) 意味着:如果我们修改一个类的的属性a,则不影响宁一个对象属性a的值
四、对象的内存解析
类中属性的使用
类中属性的使用 属性(成员变量) vs (局部变量)
1.相同点:
1.1 定义变量的格式: 数据类型 变量名 = 变量值
1.2 先声明,后使用
1.3 变量都有其对应的作用域
2.不同点:
2.1 在内中声明的位置不同 属性:直接定义在类的一对{}内 局部变量 :声明在方法内、方法形参、代码块内、构造器形参、构造器内部的变量
2.2 关于权限修饰类的不同 属性:可以在声明属性时,指定其权限,使用权限修饰符。 常用的权限修饰符:private、public、缺省、protected --> 封装性 局部变量:不可以使用权限修饰符
2.3默认初始化值的情况 属性:类的属性,根据其类型,都有默认的初始化值。(详细见数组初始化值) 局部变量,没有默认的初始化值。 意味着,我们在调用局部变量之前,一定要显示赋值。 特别的,形参在调用时,我们赋值即可。
2.4在内存中加载的位置 属性:加载到堆空间中 (非static) 局部变量加载到栈空间
类方法中的使用
方法:描述类应具有的功能 比如:Math类:sqrt() \ random() .... Scanner类: nextXxx() .... Arrays类:sort() \ binarySearch() \ toString() \equals() .....
1.举例 public void eat() {} public void sleep(int hour) {} public String getName() {} public String getNation(String nation) {}
2.方法的声明:权限修饰符 返回值类型 方法名(形参列表){ 方法体 } 3.说明: 3.1关于修饰符: java规定的4种权限修饰符:Private、public、缺省、protected
3.2 返回值类型:有返回值 vs 没有返回值
3.2.1 如果方法有返回值,则必须在方法中声明时指定返回值的类型。同时,方法中 需要使用 return 关键字来返回指定类型的变量或常量。 如果方法没有返回值,则方法声明时。使用void来表示。通常没有返回值的方法中就 不使用return,但是如果使用的话,只能"return;"表示结束方法的意思。
3.3 方法名:属于标识符,遵行标识符的规范和规则,"见名知意" 3.4 形参列表:方法可以声明0个,1个,或多个形参。
3.5 方法体:方法功能的实现。
4.return关键字的使用 1.使用范围:使用在方法体中 2.作用:(1)结束方法 (2)针对有返回值的方法。使用"return 数据"方法返回索要的数据 3.注意点:return关键字后面不可以声明执行语句。
5.方法的使用中,可以调用当前类的属性或方法 特殊的:方法A中又调用了方法A:递归方法。 方法中不可以定义方法。
自定义内存解析
匿名对象
1.理解:创建对象没有显示的赋值给一个变量名,即为匿名对象 2.特征:匿名对象只能调用一次,每次new都是一个新的对象
public class InsranceText {
public static void main(String[] args) {
phone p = new phone();
System.out.println(p);//com.atguigu.java.phone@15db9742
//有名对象
p.sendEmail();
p.playGame();
p.price = 1999;
p.showPrice();
//匿名对象
new phone().sendEmail();
new phone().playGame();
//匿名对象每次new 一个新对象,每创建一次只能调用一次
new phone().price = 1999;
new phone().showPrice();//0.0
//匿名对象的使用
PhoneMall mall = new PhoneMall();
mall.show(new phone());
}
}
class phoneMall{
public void show(phone p9hone){
phone.sendEmail();
phone.playGame();
}
}
class phone{
double price;//价格
public void sendEmail() {
System.out.println("发送邮件");
}
public void playGame() {
System.out.println("玩游戏");
}
public void showPrice() {
System.out.println("手机价格为:" + price);
}
}
方法的重载
方法的重载(overload) loading... 1.定义:在同一个类中,允许存在一个意义上的同名方法,只要它们的参数个数或者参数类型 不同即可。
"两同一不同":同一个类,相同方法名, 不同的参数列表(参数个数或者参数类型不同)
2.举例: Arrays类中重载的sort() / binarySearch()
3.判断是否是重载: 跟原方法的权限修饰符、返回值类型、形参变量名、方法体都没有关系
//如下四个方法构成重载
public void getSum(int i,int j) {
System.out.println(1);
}
public void getSum(double i,double j) {
System.out.println(2);
}
public void getSum(String i,int j) {
System.out.println(3);
}
public void getSum(int i,String j) {
System.out.println(4);
}
可变个数形参
1.jdk 5.0新增的内容
2.具体的使用
2.1 可变个数形参的格式:数据类型 ... 变量名
2.2 当调用可变个数形参的方法时,传入的参数个数可以是,0个,1个,2个....
2.3 可变个数形参的方法与本类中方法名相同,形参不同的方法之间构成重载
2.4 可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成 方法重载,换句话说,二者不能并存
2.5 可变个数形参在方法的形参中,必须声明在末尾
2.6 可变个数形参在方法的形参中,最多只能声明一个可变形参
public class MethodArgsText {
public static void main(String[] args) {
MethodArgsText test = new MethodArgsText();
test.show(4);
test.show("a");
// test.show("a","b");
test.show(8,"a","b");
}
public void show(int i) {
System.out.println(i);
}
public void show(String s) {
System.out.println(1);
}
public void show(String ... s) {
System.out.println("String ... s");
for(int i = 0;i < s.length;i++) {
System.out.println(s[i]);
}
}
public void show(int i ,String ... s) {
System.out.println(i);
}
}
方法的形参的传递机制
方法的形参的传递机制,传递值
1.形参:方法定义时,声明的小括号内的参数 实参:方法调用时,实际传递给形参的数据
2.值传递机制: 如果参数是基本数据类型,此时实参赋给形参的是实参真实储存的数据值。 如果参数是引用数据类型,此时实参赋给形参的是实参存储数据的地址值。
public class ValueTransferTest {
public static void main(String[] args) {
int n = 10;
int m = 20;
System.out.println("n = "+ n + "\t"+ "m = " + m);
//交换两个变量的值的操作
int temp = n;
n = m;
m = temp;
System.out.println("n = "+ n + "\t"+ "m = " + m);
System.out.println("***************************");
ValueTransferTest test = new ValueTransferTest();
test.swap(n, m);//这里实参的赋值是赋给swep方法的值,是真实储存的数据值
System.out.println("************************");
System.out.println("n = "+ n + "\t"+ "m = " + m);//在main方法中打印的是
//原来的值
}
public void swap(int n,int m) {
int temp = n;
n = m;
m = temp;
System.out.println("n = "+ n + "\t"+ "m = " + m);
}
}
存解析图 基本数据类型
引用数据类型:
递归
递归方法的使用 1.递归方法:一个方法体内调用它自身。 2.方法递归包含隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制。 递归方法一定要向已知方向递归,否则这种递归就变成无穷递归,类似于死循环
public class RecuersionTest {
public static void main(String[] args) {
Recuersion s = new Recuersion();
System.out.println(s.f(10));
System.out.println(s.h(9));
}
}
class Recuersion{
// 已知一个数列,f(0) = 1,f(1) = 4,f(n+2) = 2*f(n+1) + f(n),其中n是大于0的整数,
// 求f(10)的值
public int f(int i) {
if(i == 0) {
return 1;
}else if(i == 1) {
return 4;
}else {
return 2*f(i-1) + f(i-2);
}
}
//斐波那契数列
public int h(int i) {
if(i == 0) {
return 0;
}else if(i == 1) {
return 1;
}else {
return h(i-1)+h(i-2);
}
}
封装
封装性的体现: 我们将类的属性XXX私有化(private),同时,提供公共的(public)方法来获取(getXxx)和设置 (setXxx) 拓展:封装的体现:(1)如下代码 (2)不对外暴露的私有的方法 (3) 单例的模式 ...
总结:Java规定的四种权限修饰符对于属性、方法、构造器、类的体现
private:作用于类部内 < 缺省:作用于同一个包内都可以 < protected:作用于不同的子包内也可以 < public:作用于同一个工程下都可以
以下针对于属性就体现了封装性
public class AnimalTest {
public static void main(String[] args) {
Animal test = new Animal();
//test.age;//Syntax error, insert "VariableDeclarators" to
//complete LocalVariableDeclaration
// test.legs = 2;//编译不通过
// System.out.println(test.legs);
test.setLegs(4);
System.out.println(test.getLegs());
}
}
class Animal{
int age = 0;
private int legs;
String name;
public void setLegs(int i) {
if((i >= 0) && (i % 2 == 0)) {
legs = i;
}else {
legs = 0;
}
}
public int getLegs() {
return legs;
}
}
构造器
类的结构之三:构造器(或构造方法\constructor)的使用 constructor:建设者
一、构造器的使用 1.创建对象 2.初始化对象的信息
二、说明: 1.如果没有显示定义类的构造器的话,则系统默认提供一个空参的构造器 2.定义一个构造器的格式,权限修饰符 类名(形参列表){} 3.一个类中定义的多个构造器,使此构成重载 4.一旦我们显示的定义类的构造器之后,系统就不再提供默认的空参构造器 5.一个类中,至少会有一个构造器 6.构造器的默认修饰符与类的修饰符相同
三、属性赋值的先后顺序
①默认初始化值 ②显示初始化值 ③构造器中赋值 ④通过对象.方法或对象.属性的方法赋值 以上的操作顺序:①-②-③-④
public class PersonText {
public static void main(String[] args) {
Person test = new Person();
//int i = test.age; //The field Person.age is not visible
test.setAge(18);
System.out.println(test.getAge());
Person test1 = new Person(20,"Tom");
System.out.println(test1.name);
System.out.println(test1.getAge());
}
}
class Person{
//属性
private int age;
String name;
//构造器
public Person() {
}
public Person(int i,String j) {
age = i;
name = j;
}
//方法
public void setAge(int i) {
age = i;
}
public int getAge() {
return age;
}
}
javaBean
javaBean是一种Java语言的可重写的可用组件。
所谓javaBean,是指符合如下标准的Java类:
类是公共的
有一个无参的公共的构造器
有属性,且对应的get、set方法
public class Customer {
private int id;
private String name;
public Customer() {
}
public Customer(int i) {
}
public void setId(int i) {
id = i;
}
public int getId() {
return id;
}
public void setName(String k) {
name = k;
}
public String getName() {
return name;
}
}
this关键字的使用
this关键字的使用: 1.this可以用来修饰,属性、方法、构造器
2.this可以修饰属性和方法, this理解为:当前对象
2.1在类方法中,我们可以使用"this.属性"或"this.方法"的方式,调用当前对象和属性方法,但 通常情况下,我们都选择省略"this.",特殊情况下,如果方法的形参和类的属性同名时,我们必 须显示的使用"this.变量"的方式,表明变量是属性而非形参。
2.2在构造器中,我们可以使用"this.属性"或"this.方法"的方式,调用当前正在创建的对象属性 或方法,但通常情况下,我们都选择省略"this.",特殊情况下,如果方法的形参和类的属性同名 时,我们必须显示的使用"this.变量"的方式,表明变量是属性而非形参。
3.this调用构造器
(1)我们在类的构造器中,可以显示的使用"this(形参列表)"方式,调用本类中指定的其他构造器
(2)构造器中不能通过"this(形参列表)"方式调用自己
(3)如果一个类中有n个构造器,则最多有n - 1构造器中使用了"this(形参列表)"
(4)规定:"this(形参列表)"必须声明在当前构造器的首行
(5)构造器内部,最多只能声明一个"this(形参列表)",用来调用其他构造器
public class PersonTest {
public static void main(String[] args) {
Person test = new Person("haha");
System.out.println(test.getName());
}
}
class Person{
private String name;
private int age;
public Person() {
System.out.println("hello worid");
}
public Person(String name) {
this();
this.name = name;
}
public Person(int age) {
this.age = age;
}
public Person(int age,String name) {
this.age = age;
this.name = name;
}
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;
}
}
package和import关键字的使用
一、package关键字的使用 1.为了更好的实现项目中类的管理,提供包的概念 2.使用package声明类或接口所属的包,声明在源文件的首行 3.包,属于标识符,遵循标识符的命名规则,规范(xxxyyyzzz)、"见名知意" 4.每"."一次,就代表一层文件录
补充:同一个包下,不能命名同名的接口、类。 不同的包下,可以命名同名的接口、类。
二、import关键字的使用 import:导入
1.在源文件中显示的使用import结构导入指定包下的类、接口
2.声明在包的声明和类的声明之间
3.如果需要导入多个结构,则并列写出即可
4.可以使用"xxx."的方式,表示可以导入xxx包下的所有结构
5.如果使用的类或接口是java.lang包下定义的,则可以省略import结构
6.如果使用的类或接口是包下定义的,则可以省略import结构
7.如果源文件中,使用了不同包下的同名的类,则必须至少有一个类要以全类名的方式显示。
8.使用"xxx."方式表明可以调用xxx包下的所有结构,但如果使用的是xxx子包下的结构,则需要显示包名
9.import static:导入指定类或接口的竟然结构:属性或方法
MVC设计模式
实战项目一
写一个名为Account的类模拟账户。该类的属性和方法如下图所示。该类包括的属性:账号id,余额balance,年利率annuallnterestRate;包含的方法:访问器方法(getter和 setter方法),取款方法 withdraw(),存款方法 deposit()
Account页面
package com.atguigu.exer;
public class Account {
private int id;
private double balance; //余额
private double annuallnterestRate; //年利率
public Account(int id,double balance,double annuallnterestRate) {
this.id = id;
this.balance = balance;
this.annuallnterestRate = annuallnterestRate;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
public double getAnnuallnterestRate() {
return annuallnterestRate;
}
public void setAnnuallnterestRate(double annuallnterestRate) {
this.annuallnterestRate = annuallnterestRate;
}
public void withdraw(double amount) { //提款
if(balance < amount) {
System.out.println("你的余额不足");
}else {
this.balance -= amount;
}
}
public void deposit(double amount) {
if(amount > 0) {
this.balance += amount;
System.out.println("成功存入"+amount);
}
}
}
Customer 页面
package com.atguigu.exer;
public class Customer {
private String firstName;
private String lastName;
private Account account;
public Customer(String f,String l) {
this.firstName = f;
this.lastName = l;
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
}
写一个测试程序。
(1) 创建一个Customer ,名字叫Jane Smith,他有一个账号为1000,余额为2000元,年利率为1.23%的账户。
(2)对Jane Smith 操作。存入100元,再取出960元。再取出2000元。打印出Jane Smith 的基本信息。
package com.atguigu.exer;
public class CustomerTest {
public static void main(String[] args) {
Customer cust = new Customer("jane","Smith");
Account acct = new Account(1000, 2000, 0.0123);
cust.setAccount(acct);
System.out.println(cust.getAccount().getBalance()); //cust.getAccount() == acct
cust.getAccount().deposit(100);
System.out.println(cust.getAccount().getBalance());
cust.getAccount().withdraw(960);
System.out.println(cust.getAccount().getBalance());
cust.getAccount().withdraw(2000);
}
}
实战项目二
1、按照如下的UML类图,创建相应的类,提供必要的结构
在提款方法withdraw()中,需要判断用户余额是否能够满足提款数额的要求,如果不能,应给出提示。deposit()方法表示存款
account页面
public class Account {
private double balance; //余额
public Account(double init_balance) {
this.balance = init_balance;
}
public double getBalance() {
return this.balance;
}
public void withdraw(double amount) {
if (this.balance >= amount) {
this.balance -= amount;
System.out.printf("成功取出:%.1f 元\n",amount);
}
else
System.out.println("余额不足,取款失败");
}
public void deposit(double amount) {
if (amount > 0) {
this.balance += amount;
System.out.printf("成功存入:%.1f 元\n",amount);
}
}
2、按照如下的UML类图,创建相应的类,提供必要的结构
public class Customer {
private String firstName;
private String lastName;
private Account account;
public Customer(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
}
3、按照如下的UML类图,创建相应的类,提供必要的结构
public class Bank {
private Customer[] customers;
private int numberOfCustomer;
public Bank() {
customers = new Customer[10];
}
public void addCustomer(String firstName, String lastName) {
Customer cust = new Customer(firstName, lastName);
customers[numberOfCustomer++] = cust;
}
public int getNumberOfCustomers() {
return this.numberOfCustomer;
}
public Customer getCustomer(int index) {
if (index >=0 && index < this.numberOfCustomer)
return customers[index];
else
return null;
}
}
创建BankTest类,进行测试。
public class BankTest {
public static void main(String[] args) {
Bank b = new Bank();
b.addCustomer("Jane", "Smith");
b.getCustomer(0).setAccount(new Account(2000));
b.getCustomer(0).getAccount().withdraw(500);
double balance = b.getCustomer(0).getAccount().getBalance();
System.out.printf("客户:%s 的账户余额为%.1f 元\n",b.getCustomer(0).getFirstName(),balance);
b.addCustomer("Tom", "Green");
b.addCustomer("Joe", "Birden");
System.out.printf("银行的客户数量为:%d ",b.getNumberOfCustomers());
}
}
银行管理系统
customer页面
package com.hzb.p2.bean;
/**
*
* @Descripton Customer为实体对象,用来封装客户信息
* @authon HZB Email:3060542293@qq.com
* @version
* @date 2022年11月7日下午4:27:05
*/
public class Customer {
//封装客户的以下属性
private String name; //客户姓名
private char gender; //性别
private int age; //年龄
private String phone; //电话号码
private String email; //电子邮箱
//构造器
public Customer() {
}
public Customer(String name, char gender, int age, String phone, String email) {
this.name = name;
this.gender = gender;
this.age = age;
this.phone = phone;
this.email = email;
}
//各属性的get和set方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
CustomerLIst页面
package com.hzb.p2.service;
import com.hzb.p2.bean.Customer;
/**
*
* @Descripton
* @authon HZB Email:3060542293@qq.com
* @version
* @date 2022年11月7日下午4:31:12
*/
public class CustomerList {
Customer[] customers; //用来保存客户对象的数组
int total = 0; //记录已保存客户对象的数量(也可以理解为下一个要写入对象数组的索引)
/**
* 用来初始化customers数组:指定customers数组的最大空间
* @param totalCustomer
*/
public CustomerList(int totalCustomer) {
customers = new Customer[totalCustomer];
}
/**
*
* @Descripton 将指定的客户添加到数组中
* @authon HZB
* @date 2022年11月7日下午4:59:30
* @param customer
* @return TRUE:添加成功 False:添加失败
*/
public boolean addCustomer(Customer customer) {
if (total < customers.length) {
//customers[total] = customer; //把形参customer中保存的客户对象的地址值赋给数组中的元素,total可以理解为下一个要写入对象数组的索引
//total++;
customers[total++] = customer; //合并起来
return true;
} else {
return false;
}
}
/**
*
* @Descripton 修改指定索引位置的客户信息
* @authon HZB
* @date 2022年11月7日下午5:03:33
* @param index
* @param cust
* @return TRUE:添加成功 False:添加失败
*/
public boolean replaceCustomer(int index, Customer cust) {
if (index >= 0 && index < total) {
customers[index] = cust;
return true;
} else {
return false;
}
}
/**
*
* @Descripton 从数组中删除参数index指定索引位置的客户对象记录,同时index索引后的
* 客户对象索依次引往前移一格
* @authon HZB
* @date 2022年11月7日下午5:11:32
* @param index指定所删除对象在数组中的索引位置,从0开始
* @return TRUE:添加成功 False:添加失败
*/
public boolean deleteCustomer(int index) {
if (index >= 0 && index < total) {
//将索引为index之后的对象客户依次往前移一格
for (int i = index; i < total - 1; i++) {
customers[i] = customers[i + 1];
}
//customers[total - 1] = null; //同时最后存有地址值的元素需要置为null
//total--;
customers[--total] = null; //合并起来
return true;
} else {
return false;
}
}
/**
*
* @Descripton 返回数组中记录的所有客户对象
* @authon HZB
* @date 2022年11月7日下午5:21:13
* @return Customer[] 数组中包含了当前所有客户对象,该数组长度与对象个数相同
*/
public Customer[] getAllCustomers() {
Customer[] currentCustomers = new Customer[total];
//数组元素的复制
for (int i = 0; i < total; i++) {
//将customers元素保存的地址值赋给currentCustomers对应索引的元素(只是地址值的复制,并没有创建新的对象)
currentCustomers[i] = customers[i];
}
return currentCustomers;
}
/**
*
* @Descripton 返回参数index指定索引位置的客户对象记录
* @authon HZB
* @date 2022年11月7日下午5:24:11
* @param index
* @return 返回参数index指定索引位置的客户对象记录
*/
public Customer getCustomer(int index) {
if (index >= 0 && index < total) {
return customers[index];
} else {
return null;
}
}
/**
*
* @Descripton 返回当前客户对象的数量
* @authon HZB
* @date 2022年11月7日下午5:25:28
* @return
*/
public int getTotal() {
return total;
}
}
CMUtility页面
package com.hzb.p2.util;
import java.util.*;
/**
CMUtility工具类:
将不同的功能封装为方法,就是可以直接通过调用方法使用它的功能,而无需考虑具体的功能实现细节。
*/
public class CMUtility {
private static Scanner scanner = new Scanner(System.in);
/**
用于界面菜单的选择。该方法读取键盘,如果用户键入’1’-’5’中的任意字符,则方法返回。返回值为用户键入字符。
*/
public static char readMenuSelection() {
char c;
for (; ; ) {
String str = readKeyBoard(1, false);
c = str.charAt(0);
if (c != '1' && c != '2' &&
c != '3' && c != '4' && c != '5') {
System.out.print("选择错误,请重新输入:");
} else break;
}
return c;
}
/**
从键盘读取一个字符,并将其作为方法的返回值。
*/
public static char readChar() {
String str = readKeyBoard(1, false);
return str.charAt(0);
}
/**
从键盘读取一个字符,并将其作为方法的返回值。
如果用户不输入字符而直接回车,方法将以defaultValue 作为返回值。
*/
public static char readChar(char defaultValue) {
String str = readKeyBoard(1, true);
return (str.length() == 0) ? defaultValue : str.charAt(0);
}
/**
从键盘读取一个长度不超过2位的整数,并将其作为方法的返回值。
*/
public static int readInt() {
int n;
for (; ; ) {
String str = readKeyBoard(2, false);
try {
n = Integer.parseInt(str);
break;
} catch (NumberFormatException e) {
System.out.print("数字输入错误,请重新输入:");
}
}
return n;
}
/**
从键盘读取一个长度不超过2位的整数,并将其作为方法的返回值。
如果用户不输入字符而直接回车,方法将以defaultValue 作为返回值。
*/
public static int readInt(int defaultValue) {
int n;
for (; ; ) {
String str = readKeyBoard(2, true);
if (str.equals("")) {
return defaultValue;
}
try {
n = Integer.parseInt(str);
break;
} catch (NumberFormatException e) {
System.out.print("数字输入错误,请重新输入:");
}
}
return n;
}
/**
从键盘读取一个长度不超过limit的字符串,并将其作为方法的返回值。
*/
public static String readString(int limit) {
return readKeyBoard(limit, false);
}
/**
从键盘读取一个长度不超过limit的字符串,并将其作为方法的返回值。
如果用户不输入字符而直接回车,方法将以defaultValue 作为返回值。
*/
public static String readString(int limit, String defaultValue) {
String str = readKeyBoard(limit, true);
return str.equals("")? defaultValue : str;
}
/**
用于确认选择的输入。该方法从键盘读取‘Y’或’N’,并将其作为方法的返回值。
*/
public static char readConfirmSelection() {
char c;
for (; ; ) {
String str = readKeyBoard(1, false).toUpperCase();
c = str.charAt(0);
if (c == 'Y' || c == 'N') {
break;
} else {
System.out.print("选择错误,请重新输入:");
}
}
return c;
}
private static String readKeyBoard(int limit, boolean blankReturn) {
String line = "";
while (scanner.hasNextLine()) {
line = scanner.nextLine();
if (line.length() == 0) {
if (blankReturn) return line;
else continue;
}
if (line.length() < 1 || line.length() > limit) {
System.out.print("输入长度(不大于" + limit + ")错误,请重新输入:");
continue;
}
break;
}
return line;
}
}
CustomerView页面
package com.hzb.p2.ui;
import com.hzb.p2.bean.Customer;
import com.hzb.p2.service.CustomerList;
import com.hzb.p2.util.CMUtility;
/**
* @ClassName CustomerView
* @Description CustomerView为主模块,负责菜单的显示和处理用户操作
* @Author 86150
* @Date 2022/3/18 22:52
* @Version 1.0
*/
public class CustomerView {
//创建最大包含10个客户对象的 CustomerList 对象
int totalCustomer = 10;
private CustomerList customerList = new CustomerList(totalCustomer);
public CustomerView() {
//customerList.addCustomer(new Customer("张三", '男', 22, "13649090037", "3060542293@qq.com"));
}
//显示主菜单,响应用户输入,根据用户操作分别调用其他相应的成员方法(如addNewCustomer),以完成客户信息处理。
public void enterMainMenu() {
while (true) {
System.out.println("\n--------------------------------客户信息管理软件--------------------------------\n");
System.out.println(" 1 添 加 客 户");
System.out.println(" 2 修 改 客 户");
System.out.println(" 3 删 除 客 户");
System.out.println(" 4 客 户 列 表");
System.out.println(" 5 退 出 软 件\n");
System.out.print(" 请选择(1 - 5):");
char menu = CMUtility.readMenuSelection();
switch (menu) {
case '1':
addNewCustomer();
break;
case '2':
modifyCustomer();
break;
case '3':
deleteCustomer();
break;
case '4':
listAllCustomers();
break;
case '5':
System.out.print("是否确认退出(Y/N):");
char isExit = CMUtility.readConfirmSelection();
if (isExit == 'Y') {
return; //结束方法
}
}
}
}
/**
* 这四个方法分别完成“添加客户”、“修改客户”、“删除客户”和“客户列表”等各菜单功能。
* 这四个方法仅供enterMainMenu()方法调用
*/
private void addNewCustomer() {
System.out.println("\n---------------------添加客户---------------------");
if (customerList.getTotal() >= totalCustomer) {
System.out.println("----------------客户列表已满,无法添加---------------");
return;
}
System.out.print("姓名:");
String name = CMUtility.readString(10);
System.out.print("性别:");
char gender = CMUtility.readChar();
System.out.print("年龄:");
int age = CMUtility.readInt();
System.out.print("电话:");
String phone = CMUtility.readString(13);
System.out.print("邮箱:");
String email = CMUtility.readString(20);
Customer cust = new Customer(name, gender, age, phone, email);
boolean isAdded = customerList.addCustomer(cust);
if (isAdded) {
System.out.println("---------------------添加完成---------------------");
} else {
System.out.println("---------------------添加失败---------------------");
}
}
private void modifyCustomer() {
System.out.println("\n---------------------修改客户---------------------");
while (true) {
System.out.print("请选择待修改客户编号(-1退出):");
int number = CMUtility.readInt();
if (number == -1) {
return; //如果输入-1,则直接结束方法
} else if (number <= 0 || number > customerList.getTotal()) {
System.out.println("无法找到指定客户!");
} else {
System.out.print("姓名(" + customerList.getCustomer(number - 1).getName() + "):");
String newName = CMUtility.readString(10, customerList.getCustomer(number - 1).getName());
System.out.print("性别(" + customerList.getCustomer(number - 1).getGender() + "):");
char newGender = CMUtility.readChar(customerList.getCustomer(number - 1).getGender());
System.out.print("性别(" + customerList.getCustomer(number - 1).getAge() + "):");
int newAge = CMUtility.readInt(customerList.getCustomer(number - 1).getAge());
System.out.print("电话(" + customerList.getCustomer(number - 1).getPhone() + "):");
String newPhone = CMUtility.readString(13, customerList.getCustomer(number - 1).getPhone());
System.out.print("邮箱(" + customerList.getCustomer(number - 1).getEmail() + "):");
String newEmail = CMUtility.readString(20, customerList.getCustomer(number - 1).getEmail());
Customer cust = new Customer(newName, newGender, newAge, newPhone, newEmail);
boolean isReplaced = customerList.replaceCustomer(number - 1, cust);
if (isReplaced) {
System.out.println("---------------------修改完成---------------------");
} else {
System.out.println("---------------------无法修改---------------------");
}
return;
}
}
}
private void deleteCustomer() {
System.out.println("\n---------------------删除客户---------------------");
while (true) {
System.out.print("请选择待删除客户编号(-1退出):");
int number = CMUtility.readInt();
if (number == -1) {
return; //如果输入-1,则直接结束方法
} else if (number <= 0 || number > customerList.getTotal()) {
System.out.println("无法找到指定客户!");
} else {
System.out.print("确认是否删除(Y/N):");
char isDelete = CMUtility.readConfirmSelection();
if (isDelete == 'Y') {
boolean isDeleted = customerList.deleteCustomer(number - 1);
if (isDeleted) {
System.out.println("---------------------删除完成---------------------");
} else {
System.out.println("---------------------删除失败---------------------");
}
}
return;
}
}
}
private void listAllCustomers() {
System.out.println("----------------------------------客户列表----------------------------------");
if (customerList.getTotal() == 0) {
System.out.println("没有客户记录!");
} else {
System.out.println("编号\t\t姓名\t\t性别\t\t年龄\t\t电话\t\t\t\t邮箱");
Customer[] custs = customerList.getAllCustomers();
for (int i = 0; i < custs.length; i++) {
System.out.println((i + 1) + "\t\t" + custs[i].getName() + "\t\t" + custs[i].getGender() + "\t\t"
+ custs[i].getAge() + "\t\t" + custs[i].getPhone() + "\t\t" + custs[i].getEmail());
}
}
System.out.println("--------------------------------客户列表完成---------------------------------");
}
//main函数:创建CustomerView实例,并调用 enterMainMenu()方法以执行程序
public static void main(String[] args) {
CustomerView view = new CustomerView();
view.enterMainMenu();
}
}
面向对象(中)
继承
一、继承性的好处
- 减少了代码的冗余,提高了代码的复用性
- 便于功能的扩展
- 为之后的多态性的使用,提供了前提
二、继承性的格式: class A extends B {}
A:子类:派生类 subclass
B:父类:超类、基类 superclass
结果体现:一旦A继承父类B以后,子类A中就获取了父类B中所有属性和方法。(父类中声明为private的属性或方法,子类继承父类以后,仍然获取了父类中私有的结构,只是因为封装的影响,使得子类不能直接调用父类的结构而已。)
子类继承父类以后,还可以声明自己特有的属性或方法,实现功能的拓展。
extends:延伸、拓展
从过程上看:当通过子类的构造器创建子类对象时,一定会直接或间接的调用其父类的构造器,进而调用父类的父类的构造器,......直到调用了java.long.object类中空参的构造器为止。正因为才可以看到内存中父类的结构,子类的对象才可以考虑进行调用。
三、java中关于继承的规定:
- 一个类可以被多个子类继承。
- java中类的单继承性,一个子类只能有一个父类
- 子父类是相对概念。
- 子类直接继承的父类,称为:直接父类。间接继承父类称为:间接父类
- 子类继承父类以后,被获取了直接父类以及所有间接父类声明的属性和方法
四、
- 如果没有显示声明一个父类,则此类继承与java.lang.Object类
- 所有的java类(除java.lang.Object类之外)都直接或间接的继承ava.lang.Objec类
- 意味着,所有的java类具有java.lang.Object类声明的功能。
package com.hzb.java;
public class ExtendsTest {
public static void main(String[] args) {
Person p1 = new Person();
p1.eat();
p1.breath();
System.out.println("**************************");
Student s1 = new Student();
s1.eat();
s1.setName("张三");
s1.getName();
s1.breath();
}
}
class Person extends Creature {
private String name;
private int age;
public Person() {
}
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 void eat() {
System.out.println("吃饭");
}
public void sleep() {
System.out.println("睡觉");
}
}
class Student extends Person {
String major;
public Student() {
}
public Student(String major,String name, int age) {
super(name, age);
this.major = major;
}
public void Stude() {
System.out.println("学习");
}
}
class Creature{ //Student的间接父类
public void breath() {
System.out.println("呼吸");
}
}
重写 override
1.重写:子类继承父类以后,可以对父类中同名的方法,进行覆盖操作
2.应用:重写以后,当创建子类对象以后,通过子类对象调用子类中的同名同参数的方法,实际执行的是子类重写的方法
3.重写的规定:
方法的声明:权限修饰符 返回值类型 方法名(形参列表)throws 异常类型{
方法体
}
约定俗称:子类中的叫重写的方法,父类中叫别重写的方法
(1)子类重写的方法的方法名和形参列表与父类被重写的方法名和形参列表相同
(2)子类重写的方法的权限修饰符不小于被父类重写的权限修饰符
特殊情况:子类不能重写父类中声明为private权限的方法
(3)返回值类型:
父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void
父类被重写的方法的返回值类型是A类型,则子类重写的方法的返回值类型可以是A类或A类的子类
父类被重写的方法的返回值类型是基本数据类型,则子类重写的方法的返回值类型必须是相同类型的基本数据类型
(4)子类重写的方法抛出的异常不大于父类被重写的方法的抛出的异常类型
子类和父类中的同名同参的方法要么都声明为非static的(考虑重写),要么声明为static的(不是重写)
(5)区分方法重写和重载
重载和重写的方法名都相同,重写形参列表也相同,重载形参列表不相同。
重写权限修饰符不小于父类的权限修饰符,返回值特定(见上方)
重载:不表现为多态性(在方法调用之前,编译器就已经确定了所要的调用方法,这称为“早绑定”或静态绑定) 重写:表现为多态性(只等到方法调用那一刻,解释运行器才能确定所需要的具体方法,这称为“晚绑定”或“动态绑定”)
package com.hzb.java;
public class OverrideTest {
public static void main(String[] args) {
Person p1 = new Person();
p1.eat();
System.out.println("**************************");
Student s1 = new Student();
s1.eat();
s1.setName("张三");
s1.getName();
}
}
class Person {
private String name;
private int age;
public Person() {
}
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 void eat() {
System.out.println("吃饭");
}
}
class Student extends Person {
String major;
public Student() {
}
public Student(String major,String name, int age) {
super(name, age);
this.major = major;
}
public void Stude() {
System.out.println("学习");
}
public void eat() {
System.out.println("多吃肉");
}
}
super关键字的使用
1.super理解为:父类的
2.super的使用:
在子类的方法或构造器中,通过使用“super.属性”或“super.方法”的方式,显示的调用父类中声明的属性或方法,习惯省略“super.”
特殊情况,当子类和父类中定义了同名的属性时,要想在子类中调用父类中声明的属性,则必须显示使用“super.属性”的方式,表明调用的是父类中声明的属性,声明了同名的方法同理,表明调用了父类中被重写的方法。
3. super调用构造器
在子类构造器中显示使用“super(形参列表)”的方式调用父类中声明的指定的构造器
“super(形参列表)”的使用,必须声明在子类构造器的首行
因为 无论通过哪个构造器创建子类对象,需保证先初始化父类(知道父类如何为对象进行初始化),因此才继承父类的属性和方法
在构造器的首行,没有声明”this(形参列表)”或“super(形参列表)”,则默认调用父类中空参的构造器,super()
在类的构造器中,针对于”this(形参列表)”或“super(形参列表)”只能二选一,不能同时出现,且类的多个构造器中,至少有一个类的构造器中使用了“super(形参列表)”
明确:虽然创建子类对象时,调用了父类的构造器,但是自始至终就创建了一个对象,即为new 的子类对象。
package com.hzb.java;
public class OverrideTest {
public static void main(String[] args) {
Person p1 = new Person("hzb",21);
p1.eat();
System.out.println("**************************");
Student s1 = new Student("java");
}
}
class Person {
private String name;
private int age;
public Person() {
System.out.println("123"); //默认调用父类中空参的构造器,super()
}
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 void eat() {
System.out.println("吃饭");
}
}
class Student extends Person {
private String major;
public Student(String major) {
super();
}
public Student(String major,String name, int age) {
super(name, age);
this.major = major;
}
public void Stude() {
System.out.println("学习");
}
public void eat() {
System.out.println("多吃肉");
}
}
多态(运行时行为)
1.理解多态性:可以理解为一个事物的多种形态。
2.何为多态性:
对象的多态性:子类的对象赋给父类的引用
3.多态性的使用:虚拟方法调用
有了对象的多态性以后,在编译期,只能调用父类声明的方法,但是在运行时期,实际执行的是子类重写的方法。
总结:编译看走边,运行看右边
4.多态性的使用前提:①类的继承关系 ②方法的重写
5.对象的多态性:只适用方法不适用与属性(编译运行都看左边)
package com.hzb.java;
public class PersonTest {
public static void main(String[] args) {
Person1 p1 = new Man(); //子类的对象赋给父类的引用
p1.eat();
p1.Stude();
//p1.print()//编译失败,因为此时编译只看左边,person1类没有print方法
System.out.println("*********************");
Person1 p2 = new Woman();
p2.eat();
p2.Stude();
}
}
class Person1{
String name;
int age;
public void eat(){
System.out.println("人吃饭");
}
public void Stude() {
System.out.println("人学习");
}
}
class Man extends Person1{
@Override
public void eat(){
System.out.println("男人吃饭");
}
public void Stude() {
System.out.println("男人学习");
}
public void print() {
System.out.println("人帅");
}
}
class Woman extends Person1{
public void eat(){
System.out.println("女人吃饭");
}
public void Stude() {
System.out.println("女人学习");
}
}
package com.hzb.java;
public class AnimalTest {
public static void main(String[] args) {
AnimalTest animal = new AnimalTest();
animal.func(new Dog());
System.out.println("***********************");
animal.func(new Cat());
}
public void func(Animal animal) { //Animal animal = new Dog()
animal.eat();
animal.shout();
}
}
class Animal{
public void eat() {
System.out.println("动物吃");
}
public void shout() {
System.out.println("动物叫");
}
}
class Dog extends Animal{
public void eat() {
System.out.println("狗吃");
}
public void shout() {
System.out.println("狗叫");
}
}
class Cat extends Animal{
public void eat() {
System.out.println("猫吃");
}
public void shout() {
System.out.println("猫叫");
}
}
关键字instanceof
a instanceof A: 判断对象a是否是类的A的实例。如果是则返回true(父类也是true),不是返回False
使用情景:为了避免在向下转型时出现ClassCastException的异常,在向下转型之前先进行instanceof 的判断,一旦返回true,就进行向下转型,否则不进行向下转型
package com.hzb.java;
public class PersonTest {
public static void main(String[] args) {
Person p1 = new Man();
p1.sleep(); //男人睡觉
System.out.println(p1.name); //人
//只能调取子类重写的方法,不能调取子类其他方法和属性
// p1.makeMoney();
Man m1 = (Man)p1; //使用强转
m1.makeMoney(); //赚钱
// WoMan w1 = (WoMan)p1; //报错,使用强转时可能会报ClassCastException的异常
if(p1 instanceof WoMan) {
WoMan w1 = (WoMan)p1;
w1.spendMoney();
System.out.println("*****woman******");
}
if(p1 instanceof Man) {
Man w1 = (Man)p1;
w1.makeMoney();
System.out.println("*****man******");
}
if(p1 instanceof Object) {
System.out.println("*****Object******");
}
}
}
class Person{
public String name = "人";
public int age;
public void sleep() {
System.out.println("睡觉");
}
public void eat() {
System.out.println("吃");
}
}
class Man extends Person{
public int id = 001;
public String name = "man";
public void makeMoney() {
System.out.println("赚钱");
}
@Override
public void sleep() {
System.out.println("男人睡觉");
}
@Override
public void eat() {
System.out.println("男人吃");
}
}
class WoMan extends Person{
public int id = 002;
public String name = "woman";
public void spendMoney() {
System.out.println("花钱");
}
@Override
public void sleep() {
System.out.println("女人睡觉");
}
@Override
public void eat() {
System.out.println("女人吃");
}
}
练习二
public class FiledMethodTest {
public static void main(String[] args) {
Sub s = new Sub();
System.out.println(s.count); //20
s.dispaly(); //20
Base b = s;
System.out.println(b == s); //引用类型比较地址,ture
System.out.println(b.count); // 10
b.dispaly(); // 20
}
}
class Base{
int count = 10;
public void dispaly() {
System.out.println(this.count);
}
}
class Sub extends Base{
int count = 20;
public void display() {
System.out.println(this.count);
}
}
练习三
package com.hzb.exer;
/*
* 建立InstanceTest 类,在类中定义方法method(Person e);
在method 中
(1)根据 e 的类型调用相应类的 getInfo 方法。
(2)根据 e 的类型执行:
如果e 为 Person 类的对象, 输出
“a person”
如果e 为 Student 类的对象 输出:
“a student”
“a person ”
如果e 为 Graduate 类的对象,输出:
“a graduated student”
“a student”
“a person”
*/
public class InstanceTest {
public static void main(String[] args) {
InstanceTest t = new InstanceTest();
t.method(new Student());
}
public void method(Person e) {
System.out.println(e.getInfo());
if (e instanceof Graduate) {
System.out.println("a graduated student,a student, \ta person");
} else if (e instanceof Student) {
System.out.println("a student,a person");
} else {
System.out.println("a person");
}
}
}
class Person {
protected String name = "person";
protected int age = 30;
public String getInfo() {
return "name:" + name + '\n' + "age:" + age;
}
}
class Student extends Person {
protected String school = "pku";
public String getInfo() {
return "name:" + name + '\n' + "age:" + age + '\n' + "school:" + school;
}
}
class Graduate extends Student {
public String major = "IT";
public String getInfo() {
return "name:" + name + '\n' + "age:" + age + '\n' + "school:" + school + '\n' + "major:" + major;
}
}
练习4
public class InterviewTest1 {
public static void main(String[] args) {
Base base = new Sub();
base.add(1, 2, 3); //sub_1
Sub s = (Sub)base;
s.add(1,2,3); //sub_2
}
}
class Base {
public void add(int a, int... arr) {
System.out.println("base");
}
}
class Sub extends Base {
public void add(int a, int[] arr) {
System.out.println("sub_1");
}
public void add(int a, int b, int c) {
System.out.println("sub_2");
}
}
输出结果:
sub_1
sub_2
可变形参int... arr与int[] arr不能同时存在,如果同时存在,编译器会认为两个形参列表相同,参数个数确定,优先调用个数确定的方法方法。
equals方法的使用
一、运算符:==
1.可以使用基本数据类型变量和引用数据类型变量中
2.如果比较的基本数据类型变量:比较两个变量保存的数据是否相等。(不一定类型要相等)
如果比较的是引用数据类型变量:比较两个对象的地址值是否相等,即两个引用是否指向同一个对象实体。
二、equals方法的使用:
1.是一个方法而非运算符
2.只能适用于引用数据类型
3.Object类中equals()的定义和 == 作用是相同的,比较两个对象地址值是否相同。
public boolean equals(Object obj) {
return (this == obj);
}
4.像String、Date、File、包装类等都重写了Object类中的equals()方法,重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象的“实体内容”是否相同。
5.通常情况下:我们自定义类如果使用equals()的话,也通常是比较两个对象的“实体内容”是否相同,那么就需要对Object类中的equals()进行重写
package com.hzb.exer;
public class OrderTest {
public static void main(String[] args) {
Order o1 = new Order(1001,"张三");
Order o2 = new Order(1001,"张三");
System.out.println(o1.equals(o2));
}
}
class Order {
private int orderId;
private String orderName;
public int getOrderId() {
return orderId;
}
public void setOrderId(int orderId) {
this.orderId = orderId;
}
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
public Order(int orderId, String orderName) {
super();
this.orderId = orderId;
this.orderName = orderName;
}
@Override
public boolean equals(Object obj) {
if(this == obj) {
return true;
}if(obj instanceof Order) {
Order order = (Order)obj;
return this.orderId == order.orderId && this.orderName.equals(order.orderName);
}return false;
}
}
toString方法的使用
1.输出一个对象的引用时,实际上就是调用当前对象的toString()
2.Object类中toString()的定义:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
3.像String、Date、Flie、包装类等都重写了Object类中的toString()方法。使得调用对象的toString()时,返回“实体内容”信息。
4.自定义类也可以重写toString()方法,当调用此方法时,返回对象的“实体内容”。
package com.hzb.exer;
public class OrderTest {
public static void main(String[] args) {
Order o1 = new Order(1001,"张三");
System.out.println(o1.toString());//com.hzb.exer.Order@15db9742 --> Order[id =1001,name =张三]
System.out.println(o1);//com.hzb.exer.Order@15db9742
String str = new String("mm");
System.out.println(str.toString());//mm
}
}
class Order {
private int orderId;
private String orderName;
public int getOrderId() {
return orderId;
}
public void setOrderId(int orderId) {
this.orderId = orderId;
}
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
public Order(int orderId, String orderName) {
super();
this.orderId = orderId;
this.orderName = orderName;
}
@Override
public boolean equals(Object obj) {
if(this == obj) {
return true;
}if(obj instanceof Order) {
Order order = (Order)obj;
return this.orderId == order.orderId && this.orderName.equals(order.orderName);
}return false;
}
@Override
public String toString() {
return "Order[id =" + this.orderId + ",name =" + this.orderName +"]";
}
}
练习
package com.hzb.exer1;
public class CircleTest {
public static void main(String[] args) {
Circle c1 = new Circle();
Circle c2 = new Circle(1.0, "white", 1.0);
System.out.println(c1.equals(c2));
System.out.println(c1.toString());
System.out.println(c2.toString());
}
}
class GeometricObject{
protected String color;
protected double weight;
public GeometricObject() {
super();
this.color = "white";
this.weight = 1.0;
}
public GeometricObject(String color, double weight) {
super();
this.color = color;
this.weight = weight;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
}
class Circle extends GeometricObject{
private double radius;
public Circle() {
super();
this.radius = 1.0;
}
public Circle(double radius) {
super();
this.radius = radius;
}
public Circle(double radius,String color,double weight) {
super(color,weight);
this.radius = radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
public double findArea() {
return this.radius*this.radius*3.14;
}
@Override
public boolean equals(Object obj) {
if(this == obj) {
return true;
}if(obj instanceof Circle) {
Circle c = (Circle)obj;
return c.radius == this.radius;
}return false;
}
@Override
public String toString() {
return "Circle [radius=" + radius + "]";
}
}
java中的JUnit单元测试
1.单元测试java类要求:①此类是public的 ②此类提供公共的无参的构造器
2.此类中声明单元测试方法。
此时单元测试方法:方法的权限是public,没有返回值,没有形参
3.此单元测试方法上需要声明注释:@Test,并在单元测试中导入:import org.junit.jupiter.api.Test;
package com.hzb.java1;
import java.util.Date;
import org.junit.jupiter.api.Test;
public class JUnitTest {
int num = 10;
@Test
public void testEquals() {
String s1 = "mm";
String s2 = "mm";
System.out.println(s1.equals(s2));
//ClassCastException的异常
// Object obj = new String("gg");
// Date date = (Date)obj;
System.out.println(num);
show();
}
public void show() {
num = 20;
System.out.println("show..");
}
@Test
public void testToString() {
String s1 = new String("dd");
System.out.println(s1.toString());
}
}
包装类(Wrapper)的使用
针对八种基本数据类型定义相应的引用类型——包装类(封装类)
有了类的特点:就可以调用类中的方法,java才真正的面对对象
掌握的:基本数据类型、包装类、String三者之间的相互转换
自动装箱、自动拆箱、包装类-->String(parseXxx)、String-->包装类(valueOf)
package com.hzb.java1;
import org.junit.Test;
public class wrapperTest {
//基本数据类型 --> 包装类:调用包装类的构造器
@Test
public void test1(){
int num1 = 10;
Integer in1 = num1;
System.out.println(in1.toString());//10
Integer in2 = new Integer("123");//123
System.out.println(in2.toString());
//报异常
// Integer in3 = new Integer("abc123");
// System.out.println(in3.toString());
Float f1 = new Float(12.3f);
Float f2 = new Float("12.3");
System.out.println(f1); //"12.3"
System.out.println(f2); //"12.3"
Boolean b1 = new Boolean(true);
Boolean b2 = new Boolean("TrUe");
System.out.println(b1); //true
System.out.println(b2); //true
Boolean b3 = new Boolean("true123"); //不区分大小写,只要是true这几个字母就为true,否则False
System.out.println(b3); //false
Order order = new Order();
System.out.println(order.isMale); // false
System.out.println(order.isFemale); //null
}
@Test
//包装类 --> 基本数据类型:调用包装类xxx的xxxValue方法
public void test2() {
Integer in1 = new Integer(123);
int i1 = in1.intValue();
System.out.println(i1 + 1);
}
// 自动装箱与拆箱,jdk5.0新特性
@Test
public void Test3() {
//自动装箱,基本数据类型 -->包装类
int num1 = 10;
Integer in1 = num1;
System.out.println(in1); //10
boolean b1 = true;
Boolean b2 = b1;
System.out.println(b2); //true
//自动拆箱,包装类-->基本数据类型
int num2 = in1;
System.out.println(num2); //10
}
@Test
//基本数据类型、包装类-->String 类型,调用String重载的valueOf(Xxx xxx)
public void Test4() {
int num1 = 10;
// 方式一连接运算
String str1 = num1 + "";
System.out.println(str1);//"10"
// 方式二
float f1 = 123.4f;
String str2 = String.valueOf(f1);
System.out.println(str2);//"123.4"
}
@Test
public void Test5() {
String str1 = "123";
//可能会报NumberFormatException
int i1 = Integer.parseInt(str1);
System.out.println(i1 + 1);//124
String str2 = "true";
boolean b1 = Boolean.parseBoolean(str2);
System.out.println(b1);//true
}
}
class Order{
boolean isMale;
Boolean isFemale;
}
包装类面试题
package com.hzb.java1;
import org.junit.Test;
public class InterViewTest {
@Test
public void test1() {
//三元运算符后面的表达式编译时会自动统一类型
Object o1 = true ? new Integer(1):new Double(2.0);
System.out.println(o1);//1.0
}
@Test
public void test2( ) {
/*
* Integer内部定义了IntegerCache结构,IntegerCache中定义了Integer[],保存了从-128~127范 围的整数。如果我们使用自动装箱的方式,给Integer赋值的范围在
* -128~127范围内时,可以直接使用数组中的元素,不用再去new新的对象了。目的:提高效率
*/
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i == j); //false
Integer m = 1;
Integer n = 1;
System.out.println(m == n); //true
Integer x = 128; //相当于new了一个Integer对象
Integer y = 128;
System.out.println(x == y); //false
}
}
@Test
public void Test3() {
Scanner scan = new Scanner(System.in);
Vector v = new Vector();
int maxValue = 0;
for (;;) {
System.out.println("请输入一个数,负数结束");
int score = scan.nextInt();
if (score < 0) {
break;
}if(score > 100) {
System.out.println("输入的数不合法,请重新输入:");
continue;
}if(maxValue < score) {
maxValue = score;
v.addElement(score);//自动装箱
}
}
char level;
for(int i = 0;i < v.size();i++) {
Object obj = v.elementAt(i);
int score = (int)obj; //自动拆箱
if (maxValue - score <= 10)
level = 'A';
else if (maxValue - score <= 20)
level = 'B';
else if (maxValue - score <= 30)
level = 'C';
else
level = 'D';
System.out.println("student" + i + " score is " + score + ", level is " + level);
}
}
}
面向对象(下)
static关键字的使用
1.static:静态的
2.static可以用来修饰:属性、方法、代码块、内部类
3.使用static修饰属性:静态变量(或类变量)
3.1属性:按是否使用static修饰,又分为:静态属性 vs 非静态属性(实例变量)
实例变量:创建了类的多个变量,每个对象都独立的拥有一套类中的非静态属性,当修改其中一个对象中的非静态属性时,不会导致其他对象中同样的属性值的修改。
静态变量: 创建了类的多个变量,多个对象共享一个静态变量,当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过了的。
3.2 static修饰属性的其他说明
①静态变量随着类的加载而加载,可以通过“类.静态变量”的方式进行调用
②静态变量的加载要早于对象的创建。
③由于类只会加载一次,则静态变量在内存中也只会存在一份,存在方法区的静态域中。
3.3 静态属性举例:System.out; Math.PI;
4.使用static修饰方法,静态方法
静态变量随着类的加载而加载,可以通过“类.静态方法”的方式进行调用
5.static注意点:
5.1 在静态的方法内,不能使用this关键字、super关键字
5.2 关于静态属性和静态方法的使用,从生命周期去理解。
6.开发中,如何确定一个属性是否要声明为static的?
> 属性时可以被多个对象所共享的,不会随着对象的不同而不同的
开发中如何确定一个是否要声明的static:
>操作静态属性的方法,通常设置为static的
>工具类中的方法,习惯上声明为static的,比如:Math、Arrays、Collections
package com.hzb.java;
public class StaticTest {
public static void main(String[] args) {
Chinese c1 = new Chinese();
c1.setName("张三");
c1.setAge(22);
c1.setNation("中国");
System.out.println(c1.getNation());//中国
System.out.println("*************************");
Chinese c2 = new Chinese();
c1.setName("李四");
c1.setAge(23);
c1.setNation("CHN");
System.out.println(c1.getNation());//CHN
}
}
class Chinese{
private String name;
private int age;
private static String nation;
public Chinese() {
super();
}
public Chinese(String name, int age) {
super();
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 static String getNation() {
return nation;
}
public static void setNation(String nation) {
Chinese.nation = nation; //调用静态属性
}
}
练习一
package com.hzb.java;
public class AccountTest {
public static void main(String[] args) {
Account acct1 = new Account("123",120000.0);
Account acct2 = new Account("124",220000.0);
Account acct3 = new Account("125",320000.0);
System.out.println(acct1.toString());//Account [id=1001, passWord=123, Banlance=120000.0]
System.out.println(acct2.toString());//Account [id=1002, passWord=124, Banlance=220000.0]
System.out.println(acct3.toString());//Account [id=1003, passWord=125, Banlance=320000.0]
System.out.println(Account.getInterest());//0.045
System.out.println(Account.getMinBanlance());//1.0
}
}
class Account{
private int id;
private String passWord;
private double Banlance = 1.0;//存款余额
private static double minBanlance = 1.0;//最小余额
private static double interest = 0.045; //利率
private static int init = 1001;//用于自动生成id
public Account() {
super();
id = init++;
}
public Account(String passWord,double banlance) {
this();
this.passWord = passWord;
this.Banlance = banlance;
}
public String getPassWord() {
return passWord;
}
public void setPassWord(String passWord) {
this.passWord = passWord;
}
public double getBanlance() {
return Banlance;
}
public void setBanlance(double banlance) {
Banlance = banlance;
}
public int getId() {
return id;
}
public static double getMinBanlance() {
return minBanlance;
}
public static double getInterest() {
return interest;
}
@Override
public String toString() {
return "Account [id=" + id + ", passWord=" + passWord + ", Banlance=" + Banlance + "]";
}
}
单例设计模式
1.所谓类的单设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,两种实现方式 饿汉式vs懒汉式
2.区分懒汉式和饿汉式
饿汉式:
坏处:对象加载的时间长
好处:饿汉式是线程安全的
懒汉式:
好处:延时对象的创建
目前写法线程不安全,后面有修改后的
package com.hzb.java1;
//饿汉式
public class SingletonTest1 {
public static void main(String[] args) {
Bank b1 = Bank.getBank();
Bank b2 = Bank.getBank();
System.out.println(b1 == b2);//true
}
}
class Bank{
private Bank() {
}
private static Bank bank = new Bank();
public static Bank getBank() {
return bank;
}
}
package com.hzb.java1;
//懒汉式
public class SingletonTest2 {
public static void main(String[] args) {
Oder o1 = Oder.getIntance();
Oder o2 = Oder.getIntance();
System.out.println(o1 == o2);//true
}
}
class Oder{
private Oder(){
}
private static Oder intance = null;
public static Oder getIntance() {
if(intance == null) {
intance = new Oder();
}
return intance;
}
}
关于main方法的理解
package com.hzb.java1;
/*
* main()方法的使用说明:
* 1. main()方法作为程序的入口
* 2. main()方法也是一个普通的静态方法
* 3. main()方法可以作为我们与控制台交互的方式。之前:使用Scanner
*
*/
public class MainTest {
public static void main(String[] args) {
Test.main(new String[10]);
}
}
class Test{
public static void main(String[] args) {
for(int i = 0;i < args.length;i++) {
args[i] = "args_" + i;
System.out.println(args[i]);
}
}
}
代码块的使用
1.代码块的作用:用来初始化类、对象
2.代码块如果有修饰的话,只能使用static
3.分类:静态代码块 VS 非静态代码块
4.静态代码块
>内部可以有输出语句
>随着类的加载而执行
>作用:初始化类的信息
>如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
>静态代码块的执行要优先于非静态代码块的执行
>静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构
5. 非静态代码块
> 内部可以有输出语句
> 随着对象的创建而创建
> 每创建一个对象,就执行一次非静态代码块
> 作用:可在创建对象时,对对象的属性等进行初始化
>如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行
>非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、方法
6.对属性赋值先后顺序
① 默认初始化
②显式初始化 / ③ 在代码块中赋值(谁在前,谁先执行)
④ 构造器中初始化
⑤ 有了对象以后,可以通过"对象.属性"或"对象.方法"的方式,进行赋值
public class BlockTest {
public static void main(String[] args) {
String description = Person.desc;
System.out.println(description);
Person p1 = new Person();
Person p2 = new Person();
}
}
class Person{
//属性
String name;
int age;
static String desc = "I am a person";
//无参构造器
public Person() {
}
//有参构造器
public Person(String name, int age) {
this.name = name;
this.age = age;
}
//静态代码块1
static {
System.out.println("this is the first static block");
desc = "I am a person who love studying 1";
info(); // 调用静态方法,不能调用非静态方法和属性
}
//静态代码块2
static {
System.out.println("this is the second static block");
desc = "I am a person who love studying 2";
}
//非静态代码块
{
//调用静态结构与非静态结构
System.out.println("this is non-static block");
age = 20;
eat();
info();
System.out.println(desc);
}
//方法
public void eat() {
System.out.println("eat food");
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
public static void info() {
System.out.println("this is the information of man");
}
}
final关键字的使用
final :最终的
1. final可以用来修饰的结构:类、方法、变量
2. final用来修饰一个类:此洋不能被其他类所继承。
比如,String类、System类、StringBuffer类
3. final用来修饰方法:表明此方法不可以被重写
比如:Object类中getClass();
4. final用来修饰变量:此时的"变量"就称为是一个常量
4.1 final修饰属性:可以考虑赋值的位置有:显式初始化、代码块中初始化、构造器中初始化
4.2 final修饰局部变量
尤其是使用final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参
一旦赋值以后,就只能在方法体内使用此形参,但不能进行重新赋值。
5. static final用来修饰属性: 全局常量
public class FinalTest {
final int UP;
final int DOWN = 1; // 显式初始化之后, 不能再被赋值
final int LEFT;
final int RIGHT;
//代码块中 赋值
{
UP = 2;
}
//构造器中赋值, 都要赋值
public FinalTest() {
this.LEFT = 3;
this.RIGHT = 4;
}
//构造器中赋值,都要赋值
public FinalTest(int left, int right) {
this.LEFT = left;
this.RIGHT = right;
}
//不能使用方法对final修饰的属性进行赋值, 因为使用构造器创建对象后,已经对属性进行了初始化,而此时却需要调用方法对final属性赋值,矛盾
// public void setUP() {
// UP = 3;
// }
//不能对常量进行自增操作
// public void show() {
// final int num = 10;
// num++;
// }
//不能对常量重新赋值
// public void display(final int num) {
// num = 20;
//
// }
public static void main(String[] args) {
FinalTest ft1 = new FinalTest();
FinalTest ft2 = new FinalTest(6, 7);
}
}
final class A{
}
//不能继承A类
//class B extends A{
//
//}
//不能继承String类
//class C extends String{
//
//}
class D{
public final void show() {
System.out.println("final修饰的方法");
}
}
// final用来修饰方法:表明此方法不可以被重写
//class E extends D{
// public void show() {
// System.out.println("final修饰的方法");
// }
//}
abstract关键字的使用
1.abstract:抽象的
2.abstract可以修饰的的结构:类、方法
3.abstract修饰类:抽象类
> 此类不能实例化
> 抽象类中一定有构造器,便于子类实例化时调用(设计,子类对象实例化的全过程)
> 开发中,都会提供抽象类的子类,让子类对象实例化,完成相关操作
4.abstract修饰方法:抽象方法
> 抽象方法只有方法的声明,没有方法体
> 包含抽象方法的类,一定是一个抽象类,反之,抽象类中可以没有抽象方法
> 若子类重写了父类中的所有的抽象方法后,此子类方可实例化
若子类没有重写父类中的所有的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰
package com.hzb.java;
public class AbstractTest {
public static void main(String[] args) {
// 类一旦加了abstract就是抽象类,就不可以实例化了
// Person p1 = new Person();//Cannot instantiate the type Person
Man m1 = new Man(22,"hzb");
m1.eat();
}
}
//抽象类
abstract class Person {
private int age = 21;
private String name;
public Person() {
}
public Person(int age, String name) {
super();
this.age = age;
this.name = name;
}
public int getAge() {
return this.age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// 抽象方法,它一定存在于抽象类中
public abstract void eat();
public void walk() {
}
}
class Man extends Person{
public Man() {
}
public Man(int age,String name) {
super(age,name);
}
@Override
public void eat() {
System.out.println("男人吃饭");
}
}
抽象类的匿名子类
package com.hzb.exer1;
import com.hzb.exer2.Manager;
public class EmployeeTest {
public static void main(String[] args) {
Manager m1 = new Manager();//非匿名类,非匿名对象
method(new Manager());//非匿名类,匿名对象
//创建匿名子类对象
Employee e1 = new Employee() {
@Override
public void work() {
System.out.println("匿名类工作");
}
};
method(e1); //匿名类工作
//创建匿名子类,匿名对象
method(new Employee() {
@Override
public void work() {
System.out.println("匿名类匿名对象工作");
}
};
}
public static void method(Employee e) {
e.work();
}
}
package com.hzb.exer1;
public abstract class Employee {
private String name;
private int id;
private int salary;
public Employee() {
}
public Employee(String name, int id, int salary) {
super();
this.name = name;
this.id = id;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public abstract void work();
}
private int bonus;//奖金
public Manager() {
super();
}
public Manager(String name,int id,int salary,int bonus) {
super(name,id,salary);
this.bonus = bonus;
}
@Override
public void work() {
System.out.println("员工工资");
}
模板方法设计模式
抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式
package com.hzb.java;
public class TemplateTset {
public static void main(String[] args) {
Template s1 = new SubTemplate();
s1.spendTime();
}
}
abstract class Template{
public void spendTime() {
long start = System.currentTimeMillis();
code();
long end = System.currentTimeMillis();
System.out.println("\n花费的时间为:" + (end-start) + "ms");
}
public abstract void code();
}
class SubTemplate extends Template{
@Override
public void code() {
for(int i = 2;i <= 100;i++) {
boolean isFlag = true;
for(int j = 2;j <= Math.sqrt(i);j++) {
if(i % j == 0) {
isFlag = false;
break;
}
}
if(isFlag) {
System.out.print(i + " ");
}
}
}
}
练习
package com.hzb.exer4;
import java.util.Calendar;
public class EmployeeTest {
public static void main(String[] args) {
方式一:
// Scanner scanner = new Scanner(System.in);
// System.out.println("请输入当月的月份:");
// int month = scanner.nextInt();
// 方式二:
Calendar calendar = Calendar.getInstance();
int month = calendar.get(Calendar.MONTH);//获取当前的月份
// System.out.println(month);//一月份:0
Employee[] e = new Employee[2];
e[0] = new SalarideEmployee("张三", 1001, new MyDate(2000, 6, 6), 20000);
e[1] = new HourlyEmployee("李四", 1002, new MyDate(2000, 1, 6), 50, 160);
for (int i = 0; i < e.length; i++) {
System.out.println(e[i].toString());
if ((month + 1) == e[i].getBirthday().getMonth()) {
System.out.println("生日快乐!奖励 100 元");
}
}
}
}
abstract class Employee {
private String name;
private int number;
private MyDate birthday;
public Employee() {
}
public Employee(String name, int number, MyDate birthday) {
super();
this.name = name;
this.number = number;
this.birthday = birthday;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public MyDate getBirthday() {
return birthday;
}
public void setBirthday(MyDate birthday) {
this.birthday = birthday;
}
public abstract double earnings();
@Override
public String toString() {
return "name=" + name + ", number=" + number + ", birthday=" + birthday.toDateString() + ",";
}
}
class MyDate {
private int year;
private int month;
private int day;
public MyDate() {
super();
}
public MyDate(int year, int month, int day) {
super();
this.year = year;
this.month = month;
this.day = day;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
public String toDateString() {
return year + "年" + month + "月" + day + "天";
}
}
class SalarideEmployee extends Employee {
private double monthlySalary;
public SalarideEmployee() {
super();
}
public SalarideEmployee(String name, int number, MyDate birthday, double monthlySalary) {
super(name, number, birthday);
this.monthlySalary = monthlySalary;
}
@Override
public double earnings() {
return this.monthlySalary;
}
@Override
public String toString() {
return "SalarideEmployee[" + super.toString() + "月工资为:" + monthlySalary + "]";
}
}
class HourlyEmployee extends Employee {
private int wage;
private double hour;
public HourlyEmployee(int wage, double hour) {
super();
this.wage = wage;
this.hour = hour;
}
public HourlyEmployee(String name, int number, MyDate birthday, int wage, double hour) {
super(name, number, birthday);
this.wage = wage;
this.hour = hour;
}
public int getWage() {
return wage;
}
public void setWage(int wage) {
this.wage = wage;
}
public double getHour() {
return hour;
}
public void setHour(double hour) {
this.hour = hour;
}
@Override
public double earnings() {
return wage * hour;
}
@Override
public String toString() {
return "HourlyEmployee [" + super.toString() + "月工资为:" + earnings() + "]";
}
}
接口的使用
1.接口使用interface来定义
2.java中,接口和类是并列的结构
3.如何定义接口:定义接口中的成员
3.1 JDK7及以前,只能定义全局变量和抽象方法
> 全局常量:public static final 的,但是书写时可以省略不写
> 抽象方法:public abstract 的
3.2 JDK8,除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法
4.接口中不能定义构造器的!意味着接口不可以实例化
5.java开发中,接口通过让类实现(implements)的方法来使用。
如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化
如果实现类没有覆盖接口中所有抽象方法,则此实现类仍为一个抽象类
6.java可以实现多个接口 --> 弥补了java单继承的局限性
格式:class AA extends BB implements CC,DD,EE
7.接口与接口之间可以继承,而且是可以多继承
8.接口的具体使用,体现多态性接口的主要用途就是被实现类实现。(面向接口编程)
9.接口,实际可以看作是一种规范
面试题:抽象类与接口有哪些异同?
见 抽象类与接口的异同点_Aure219的博客-CSDN博客_抽象类和接口的异同点
package com.hzb.java1;
public class InterfaceTest {
public static void main(String[] args) {
}
}
interface Flayable{
//全局变量
public final int MAX_SPEEND = 700;
public final int MIN_SPEEND = 1;
//抽象方法
public abstract void fly();
void stop();//省略了 public abstract
//Interfaces cannot have constructors
// public Flayable(){
//
// }
}
interface Attackable{
void attack();
}
class plane implements Flayable{
@Override
public void fly() {
System.out.println("飞机通过引擎起飞");
}
@Override
public void stop() {
System.out.println("驾驶员减速停止");
}
abstract class Kite implements Flayable{
@Override
public void fly() {
}
}
class Bullet extends Object implements Flayable,Attackable,CC{
@Override
public void attack() {
// TODO Auto-generated method stub
}
@Override
public void fly() {
// TODO Auto-generated method stub
}
@Override
public void stop() {
// TODO Auto-generated method stub
}
@Override
public void method1() {
// TODO Auto-generated method stub
}
@Override
public void method2() {
// TODO Auto-generated method stub
}
}
//*********************************
interface AA{
void method1();
}
interface BB{
void method2();
}
interface CC extends AA,BB{
}
}
接口的使用
1.接口使用上也满足多态性
2.接口,实际上就是定义了一种规范
3.开发中,体会面向接口编程!
package com.hzb.java1;
public class USBTest {
public static void main(String[] args) {
Computer c = new Computer();
//1.创建了接口的非匿名实现类的非匿名对象
Flash f = new Flash();
c.transferData(f);
//2.创建了接口的非匿名实现类的匿名对象
c.transferData(new printer());
//3.创建了接口的匿名实现类的非匿名对象
USB phone = new USB() {
@Override
public void start() {
System.out.println("手机开始工作");
}
@Override
public void stop() {
System.out.println("手机结束工作");
}};
//4.创建了接口的匿名实现类的匿名对象
c.transferData(new USB(){
@Override
public void start() {
System.out.println("mps开始工作");
}
@Override
public void stop() {
System.out.println("mps结束工作");
}});
}
}
class Computer{
public void transferData(USB usb) { // USB usb = new Flash();
usb.start();
System.out.println("具体传输数据的细节");
usb.stop();
}
}
interface USB{
//定义了规范
public abstract void start();
public abstract void stop();
}
class Flash implements USB{
@Override
public void start() {
System.out.println("U盘开始工作");
}
@Override
public void stop() {
System.out.println("U盘结束工作");
}
}
class printer implements USB{
@Override
public void start() {
System.out.println("打印机开始工作");
}
@Override
public void stop() {
System.out.println("打印机结束工作");
}
}
代理模式
分类:
- 静态代理(静态定义代理类)
- 动态代理(动态生成代理类) JDK 自带的动态代理,需要反射等知识
package com.hzb.java1;
public class NetWorkTest {
public static void main(String[] args) {
ProxyServer p = new ProxyServer(new Server());
p.check(); // 代理服务器校验
p.browse();//真实的服务器来访问网络
}
}
interface NetWork{
void browse();
}
//被代理类
class Server implements NetWork{
@Override
public void browse() {
System.out.println("真实的服务器来访问网络");
}
}
//代理类
class ProxyServer implements NetWork{
private NetWork work;
public ProxyServer(NetWork work) {
super();
this.work = work;
}
public void check() {
System.out.println("代理服务器校验");
}
@Override
public void browse() {
work.browse();
}
}
package com.hzb.java1;
public class StaticProxyTest {
public static void main(String[] args) {
Proxy s = new Proxy(new RealStar());
s.confer();
s.signContract();
s.bookTicket();
s.sing();
s.collectMoney();
}
}
interface Star{
void confer();// 面谈
void signContract();// 签合同
void bookTicket();// 订票
void sing();// 唱歌
void collectMoney();// 收钱
}
//被代理类
class RealStar implements Star{
@Override
public void confer() {
}
@Override
public void signContract() {
}
@Override
public void bookTicket() {
}
@Override
public void sing() {
System.out.println("明星:歌唱啊哈哈");
}
@Override
public void collectMoney() {
}
}
//代理类
class Proxy implements Star{
private Star real;
public Proxy(Star real) { //Star real = new RealStar()
this.real = real;
}
public void confer() {
System.out.println("经纪人面谈");
}
public void signContract() {
System.out.println("经纪人签合同");
}
public void bookTicket() {
System.out.println("经纪人订票");
}
public void sing() {
real.sing();
}
public void collectMoney() {
System.out.println("经纪人收钱");
}
}
接口【面试题】排错:
interface A {
int x = 0;
}
class B {
int x = 1;
}
class C extends B implements A {
public void pX() {
// 编译不通过,x 不明确
System.out.println(x);
// System.out.println(super.x); //1
// System.out.println(A.x);//0
}
public static void main(String[] args) {
new C().pX();
}
}
interface Playable {
void play();
}
interface Bounceable {
void play();
}
interface Rollable extends Playable, Bounceable {
Ball ball= new Ball("PingPang"); //省略了 public static final
}
public class Ball implements Rollable {
private String name;
public String getName() {
return name;
}
public Ball(String name) {
this.name= name;
}
public void play() {
ball = new Ball("Football"); //ball已经被final修饰无法被修改
System.out.println(ball.getName());
}
}
练习
package com.hzb.exer5;
public class InterfaceTest {
public static void main(String[] args) {
ComparableCircle c1 = new ComparableCircle(2.9);
ComparableCircle c2 = new ComparableCircle(2.8);
System.out.println(c1.compareTo(c2));
int compareValue = c1.compareTo(c2);
if(compareValue > 0){
System.out.println("c1 对象大");
}else if(compareValue < 0){
System.out.println("c2 对象大");
}else{
System.out.println("两个一样的");
}
int compareValue1 = c1.compareTo(new String("AA"));
System.out.println(compareValue1); //0
}
}
interface CompareObject{
int compareTo(Object obj);
}
class Circle{
private double redius;
public double getRedius() {
return redius;
}
public void setRedius(double redius) {
this.redius = redius;
}
}
class ComparableCircle extends Circle implements CompareObject{
public ComparableCircle(double redius) {
super();
this.setRedius(redius);
}
public ComparableCircle() {
super();
}
@Override
public int compareTo(Object obj) {
if(this == obj) {
return 0;
}if(obj instanceof Circle) {
Circle c = (Circle)obj;
if(this.getRedius() > c.getRedius()) {
return 1;
}else if(this.getRedius() < c.getRedius()) {
return -1;
}else {
return 0;
}
}else {
return 0;
}
}
}
java8接口新特性
package com.hzb.java1;
/* 知识点1: 接口中定义的静态方法,只能通过接口来调用。
* 知识点2: 通过实现类的对象,可以调用接口中的默认方法, 如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法
* 知识点3: 如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的方法,
* 那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法。--->类优先原则
* 知识点4: 如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,//那么在实现类没有重写此方法的情况下,报错。-->接口冲突。
* 如:class SubClass implements CompareA, CompareB
* 知识点5: 如何在子类(或实现类)的方法中调用父类、接口中被重写的方法
*/
public class Java8Test {
public static void main(String[] args) {
//知识点1: 接口中定义的静态方法,只能通过接口来调用
CompareA.methd1();
//通过实现类的对象,可以调用接口中的默认方法,
SubClass sc = new SubClass();
sc.method2(); // 如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法
sc.method3();
sc.ordinaryMethod();
}
}
//接口CompareA
interface CompareA{
//静态方法
public static void methd1(){
System.out.println("CompareA: beijing");
}
// 默认方法
public default void method2() {
System.out.println("CompareA: shanghai");
}
default void method3() {
System.out.println("CompareA : tokyo");
}
}
//接口CompareB
interface CompareB{
default void method3() {
System.out.println("CompareA : kyoto");
}
}
class SuperClass{
public void method3() {
System.out.println("CompareA : Berlin");
}
}
class SubClass extends SuperClass implements CompareA, CompareB{
public void method2() {
System.out.println("CompareA : NewYork");
}
@Override
public void method3() {
// TODO Auto-generated method stub
System.out.println("CompareB : London");
}
//知识点5: 如何在子类(或实现类)的方法中调用父类、接口中被重写的方法
public void ordinaryMethod() {
method3(); //调用subclass类中重写的methd3()方法
super.method3(); // 调用的是父类中声明的method3()方法
//调用接口中的默认方法
CompareA.super.method3();
CompareB.super.method3();
}
}
内部类的使用
package com.hzb.java1;
/*
* 类的内部成员之五:内部类
* 1. Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类
*
* 2. 内部类的分类:成员内部类(静态、非静态)MS局部内部类(方法内、代码块内、构造器内)
*
* 3. 成员内部类:
* 一方面,作为外部类的成员:
* > 调用外部类的结构
* > 可以被static修饰
* > 可以被4种不同的权限修饰
* 另一方面,作为一个类:
* > 类内可以定义属性、方法、构造器等
* > 可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承
* > 可以被abstract修饰
*
* 4. 关注如下的3个问题
* 4.1 如何实例化成员内部类的对象
* 4.2 如何在成员内部类中区分调用外部类的结构
* 4.3 开发中局部内部类的使用
* 4.4 开发中局部内部类的使用,见《InnerClassTest1.java》
*
*/
public class InnerClassTest {
public static void main(String[] args) {
// 创建Dog实例(静态的成员内部类):
People.Dog dog = new People.Dog();
dog.show();
// 创建Bird实例(非静态的成员内部类)∶
People p = new People();
People.Bird bird = p.new Bird();
bird.sing();
System.out.println("***************************");
bird.display("jack");
}
}
class People{
String name = "People";
public void eat() {
System.out.println("people eat rice");
}
//静态成员内部类
static class Dog{
String name = "Dog";
int age;
public void show() {
System.out.println("kala is a dog");
}
// eat(); // 静态成员内部类不能调用外部类的非静态方法
}
//非静态成员内部类
class Bird{
String name = "Bird";
public Bird() {
}
public void sing() {
System.out.println("bird can sing");
People.this.eat(); //调用外部内的非静态方法
}
public void display(String name) {
System.out.println(name); // 方法的形参
System.out.println(this.name); // 内部类的属性
System.out.println(People.this.name); // 外部类的属性
}
}
}
InnerClassTest1
package com.hzb.java1;
public class InnerClassTest1 {
//返回一个实现了Comparable接口的类的对象
//创建一个实现了Comparable接口的类:局部内部类
//方式—:
// public static Comparable getComparable() {
// class MyComparable implements Comparable{
//
// @Override
// public int compareTo(Object o) {
// return 0;
// }
// }
// return new MyComparable();
// }
//方式二:匿名类的匿名对象
public static Comparable getComparable() {
return new Comparable(){
@Override
public int compareTo(Object o) {
return 0;
}
};
}
public static void main(String[] args) {
Comparable c = getComparable();
System.out.println(c.getClass()); //InnerClassTest1$1MyComparable
}
}
局部内部类的使用注意
public class InnerClassTest {
// public void onCreate(){
//
// int number = 10;
//
// View.OnClickListern listener = new View.OnClickListener(){
//
// public void onClick(){
// System.out.println("hello!");
// System.out.println(number);
// }
//
// }
//
// button.setOnClickListener(listener);
//
//}
/*
* 在局部内部类的方法中(比如:show)如果调用局部内部类所声明的方法(比如:method)中的局部变量(比如:num)的话,
* 要求此局部变量声明为final的。
*
* jdk 7及之前版本:要求此局部变量显式的声明为final的
* jdk 8及之后的版本:可以省略final的声明
*
*/
public void method(){
//局部变量
int num = 10;
class AA{
public void show(){
// num = 20; //Local variable num defined in an enclosing scope must be final or effectively final
System.out.println(num);
}
}
}
}
异常处理
异常概述与异常体系结构
package com.hzb.java;
/*
* java.lang.Throwable
* |-----java.lang.Error: 一般不编写针对性的代码进行处理。
* |-----java.lang.Exception: 可以进行异常的处理
* |-----编译时异常(checked)
* |-----IOException
* |-----FileNotFoundException
* |-----ClassNotFoundException
* |-----运行时异常(unchecked)
* |-----NullPointerException
* |-----ArrayIndexOutOfBoundsException
* |-----ClassCastException
* |-----NumberFormatException
* |-----InputMismatchException
* |-----ArithmeticException
*
*/
import java.io.FileInputStream;
import java.util.Date;
import java.util.Scanner;
import javax.imageio.stream.FileImageInputStream;
import org.junit.jupiter.api.Test;
//***************常见的异常************************
public class ExceptionTest {
//运行时异常
//NullPointerException 空指针异常
@Test
public void test1() {
String str = null;
System.out.println(str.charAt(3));
}
//ArrayIndexOutOfBoundsException 数组角标越界异常
@Test
public void test2() {
int[] arr = new int[10];
System.out.println(arr[10]);
String str = "abc";
System.out.println(str.charAt(3));
}
//ClassCastException 类型转换异常
@Test
public void test3() {
Object obj = new Date();
String str = (String)obj;
}
//NumberFormatException 数字格式化异常
@Test
public void test4() {
String str = "abc";
int num = Integer.parseInt(str);
System.out.println(num);
}
//InputMismatchException
@Test
public void test5() {
Scanner sc = new Scanner(System.in);
int score = sc.nextInt();
System.out.println(score);
}
//ArithmeticException 除数为0,算数异常
@Test
public void test6() {
int a = 10;
int b = 0;
System.out.println(a / b);
}
//编译时异常
//FileNotFoundException 找不到文件
@Test
public void test7() {
// File file = new File("hello.txt");
// FileInputStream fis = new FileImageInputStream(file);
// int data = fis.read();
// while (data != -1) {
// System.out.println((char)data);
// data = fis.read();
// }
}
}
异常处理机制一:try - catch - finally
一、异常的处理:抓抛模型
过程一: "抛": 程序在正常执行的过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象。并将此对象抛出。
一旦抛出对象以后,其后的代码就不再执行。
过程二: "抓": 可以理解为异常的处理方式: try-catch-finally throws
二、try-catch-finally的使用
try{
//可能出现异常的代码
}catch(异常类型1 变量名1){
//异常处理的方式1
}catch(异常类型2 变量名2){
//异常处理的方式2
}catch(异常类型3 变量名3){
//异常处理的方式3
}
......
finally{
//一定会执行的代码
}
说明:
1. finally是可选的,不一定非要写。
2.使用try将可能出现异常代码包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对彭的类型,去catch中进行匹配
3.一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常的处理。一旦处理完成,就跳出当前的try-catch结构(在没有写finally的情况)。继续执行其后的代码
4. catch中的异常类型如果没有子父类关系,则谁声明在上,谁声明在下无所谓。
catch中的异常类型如果满足子父类关系,则要求子类一定声明在父类的上面。否则,报错
5. 常用的异常对象处理的方式: ① String getMessage() ② printstackTrace()
6. 在try结构中声明的变量,再出了try结构以后,就不能再被调用
体会1: 使用try-catch-finally处理编译时异常,是得程序在编译时就不再报错,但是运行时仍可能报错。
相当于我们使用try-catch-finally将一个编译时可能出现的异常,延迟到运行时出现。
体会2: 开发中,由于运行时异常比较常见,所以通常就不针对运行时异常编写try-catch-finally了。
针对于编译时异常,我们一定要考虑异常的处理。
package com.hzb.java;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.InputMismatchException;
import java.util.Scanner;
import javax.imageio.stream.FileImageInputStream;
import org.junit.jupiter.api.Test;
public class ExceptionTest1 {
@Test
public void test1(){
String str = null;
try {
str = "abc";
int num = Integer.parseInt(str);
System.out.println("1");
}catch(NumberFormatException e) {
e.printStackTrace(); // java.lang.NumberFormatException: For input string: "abc"
}
catch (Exception e) {
e.printStackTrace();
}
System.out.println("2");
}
@Test
public void Test2() {
try {
File file = new File("hello.txt");
FileInputStream fis = new FileInputStream(file);
int data = fis.read();
while (data != -1) {
System.out.println((char)data);
data = fis.read();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void test3() {
Scanner sc = new Scanner(System.in);
int score = 0;
try {
score = sc.nextInt();
}catch (InputMismatchException e){
e.printStackTrace();
}catch (Exception e) {
e.printStackTrace();
}
System.out.println(score);
}
}
finally的使用
try-catch-finally中finally的使用:
1. finally是可选的
2. finally中声明的是一定会被执行的代码。即使catch中又出现异常了,try中有return语句 catch中有return语句等情况。
package com.hzb.java;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.junit.jupiter.api.Test;
public class FinallyTest {
@Test
public void test1() {
try {
int a = 10;
int b = 0;
System.out.println(a / b);
} catch (ArithmeticException e) {
int[] arr = new int[10];
System.out.println(arr[10]);
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("hello finally");
}
}
@Test
public void test2() {
int num = method();
System.out.println(num);
}
private int method() {
try {
int[] arr = new int[10];
System.out.println(arr[10]);
return 1;
} catch (IndexOutOfBoundsException e) {
e.printStackTrace();
return 2;
} finally {
System.out.println("我一定会执行");
return 3;
}
}
@Test
public void test3() {
FileInputStream fis = null;
try {
File file = new File("hello.txt");
fis = new FileInputStream(file);
int data = fis.read();
while (data != -1) {
System.out.println((char)data);
data = fis.read();
}
}catch (FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}finally {
try {
if(fis != null) {
fis.close();
}
}catch(IOException e) {
e.printStackTrace();
}
}
}
}
异常处理机制二:声明抛出异常 throw
异常处理的方式二: throws + 异常类型
1. "throws +异常类型"写在方法的声明处。指明此方法执行时,可能会抛出的异常类型。一旦当方法体执行时,出现异常,仍会在异常代码处生成一个异常类的对象,此对象满足throws后异常类型时,就会被抛出 异常代码后续的代码,就不再执行!
2.体会: try-catch-finally: 真正的将异常给处理掉了。 throws的方式只是将异常抛给了方法的调用者。并投有真正将异常处理掉。
package com.hzb.java1;
/*
* 方法重写的规则之一:
* 子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型
*
* 3.开发中如何选择使用try-catch-finally 还是使用throws?
* 3.1 如果父类中被重写的方法没有throws方式处理异常,则子类重写的方法也不能使用throws,意味着如果
* 子类重写的方法中有异常,必须使用try-catch-finally方式处理。
* 3.2 执行的方法a中,先后又调用了另外的几个方法,这几个方法是递进关系执行的。我们建议这几个方法使用throw的方式进行处理。
* 而执行的方法a可以考虑使用try-catch-finally方式进行处理。
*
*/
import java.io.FileNotFoundException;
import java.io.IOException;
public class OverrideTest {
public static void main(String[] args) {
OverrideTest t = new OverrideTest();
t.display(new SubClass());
}
public void display(SuperClass s) {
try {
s.show();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class SuperClass{
public void show() throws IOException{
System.out.println("SperClass Exception");
}
}
class SubClass extends SuperClass{
public void show() throws FileNotFoundException{
System.out.println("SubClass Exception");
}
}
package com.hzb.java1;
/*
* 方法重写的规则之一:
* 子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型
*
* 3.开发中如何选择使用try-catch-finally 还是使用throws?
* 3.1 如果父类中被重写的方法没有throws方式处理异常,则子类重写的方法也不能使用throws,意味着如果
* 子类重写的方法中有异常,必须使用try-catch-finally方式处理。
* 3.2 执行的方法a中,先后又调用了另外的几个方法,这几个方法是递进关系执行的。我们建议这几个方法使用throw的方式进行处理。
* 而执行的方法a可以考虑使用try-catch-finally方式进行处理。
*
*/
import java.io.FileNotFoundException;
import java.io.IOException;
public class OverrideTest {
public static void main(String[] args) {
OverrideTest t = new OverrideTest();
t.display(new SubClass());
}
public void display(SuperClass s) {
try {
s.show();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class SuperClass{
public void show() throws IOException{
System.out.println("SperClass Exception");
}
}
class SubClass extends SuperClass{
public void show() throws FileNotFoundException{
System.out.println("SubClass Exception");
}
}
手动抛出异常
关键字:throw
用法:throw new 异常类(“Message”)
package com.hzb.java2;
public class ExceptionTest3 {
public static void main(String[] args) {
try {
Student.replay(0);
} catch (Exception e) {
// e.printStackTrace();
System.out.println(e.getMessage());
}
}
}
class Student{
private static int id;
public static void replay(int id1) throws Exception{
if(id1 > 0) {
id = id1;
}else {
throw new Exception("您输入的数据违法");
}
}
}
用户自定义异常
如何自定义异常类?
1.继承于现有的异常结构:RuntimeException 、Exception
2.提供全局常量:serialVersionUID
3.提供重载的构造器
package com.hzb.java2;
public class StudentTest1{
public static void main(String[] args) {
Student1 s = new Student1();
try {
s.replay(0);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
class Student1{
private int id;
public void replay(int id) throws MinusException{
if(id > 0) {
this.id = id;
}else {
throw new MinusException("您输入的数据是负数");
}
}
}
class MinusException extends RuntimeException {
static final long serialVersionUID = -70348971907466939L;
public MinusException() {
super();
}
public MinusException(String messge) {
super(messge);
}
}
练习
package com.hzb.exer1;
/*
* 编写应用程序EcmDef.java,接收命令行的两个参数,
* 要求不能输入负数,计算两数相除。
* 对 数 据 类 型 不 一 致(NumberFormatException)、
* 缺 少 命 令 行 参 数(ArrayIndexOutOfBoundsException、
* 除0(ArithmeticException)及输入负数(EcDef自定义的异常)进行异常处理。
*
* 提示:
* (1)在主类(EcmDef)中定义异常方法(ecm)完成两数相除功能。
* (2)在main()方法中使用异常处理语句进行异常处理。
* (3)在程序中,自定义对应输入负数的异常类(EcDef)。
* (4)运行时接受参数java EcmDef2010//args[0]=“20”args[1]=“10”
* (5)Interger类的static方法parseInt(Strings)将s转换成对应的int值。
* 如:int a=Interger.parseInt(“314”);//a=314;
*/
public class EcmDef {
public static void main(String[] args) {
try {
int i = Integer.parseInt(args[0]);
int j = Integer.parseInt(args[1]);
int num = ecm(i, j);
System.out.println(num);
} catch (NumberFormatException e) {
System.out.println("对数据类型不一致");
} catch(ArrayIndexOutOfBoundsException e ) {
System.out.println("缺少命令行参数");
} catch(ArithmeticException e) {
System.out.println("除0");
} catch(EcDef e) {
System.out.println(e.getMessage());
}
}
public static int ecm(int i,int j) throws EcDef{
if(i < 0 || j < 0) {
throw new EcDef("数字为负数");
} return i / j;
}
}
class EcDef extends Exception{
static final Long UID = 12324343l;
public EcDef() {}
public EcDef(String message) {
super(message);
}
}