第5章_方法的定义/调用/重载 方法的定义和调用 【1】什么是方法? 方法(method)就是一段用来完成特定功能的代码片段,类似于其它语言的函数(function)。 方法用于定义该类或该类的实例的行为特征和功能实现。 方法是类和对象行为特征的抽象。方法很类似于面向过程中的函数。面向过程中,函数是最基本单位,整个程序由一个个函数调用组成。面向对象中,整个程序的基本单位是类,方法是从属于类和对象的。
【2】方法声明格式: [修饰符1 修饰符2 …] 返回值类型 方法名(形式参数列表){ Java语句;… … … }
【3】方法的调用方式: 对象名.方法名(实参列表) 【4】方法的详细说明 形式参数:在方法声明时用于接收外界传入的数据。 实参:调用方法时实际传给方法的数据。 返回值:方法在执行完毕后返还给调用它的环境的数据。 返回值类型:事先约定的返回值的数据类型,如无返回值,必须显示指定为为void。
【5】代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public class TestMethod01 { public static int add (int num1,int num2) { int sum = 0 ; sum += num1; sum += num2; return sum; } public static void main (String[] args) { int num = add(10 ,20 ); System.out.println(num); int sum = add(30 ,90 ); System.out.println(sum); System.out.println(add(50 ,48 )); } }
【6】总结:
1.方法是:对特定的功能进行提取,形成一个代码片段,这个代码片段就是我们所说的方法 2.方法和方法是并列的关系,所以我们定义的方法不能写到main方法中 3.方法的定义–》格式: 修饰符 方法返回值类型 方法名(形参列表){ 方法体; return 方法返回值; }
4.方法的作用:提高代码的复用性 5.总结方法定义的格式:
修饰符: 暂时使用public static —>面向对象一章讲解 方法返回值类型 : 方法的返回值对应的数据类型 数据类型: 可以是基本数据类型(byte,short,int,long,float,double,char,boolean) 也可以是引用数据类型 方法名 :见名知意,首字母小写,其余遵循驼峰命名, eg: addNum ,一般尽量使用英文来命名 形参列表 :方法定义的时候需要的形式参数 : int num1, int num2 –>相当于告诉方法的调用者:需要传入几个参数,需要传入的参数的类型 实际参数:方法调用的时候传入的具体的参数: 10,20 –>根据形式参数的需要传入的 5)方法体:具体的业务逻辑代码 6. return 方法返回值; 方法如果有返回值的话: return+方法返回值,将返回值返回到方法的调用处 方法没有返回值的话:return可以省略不写了,并且方法的返回值类型为:void
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class TestMethod02 { public static void add (int num1,int num2) { int sum = 0 ; sum += num1; sum += num2; System.out.println(sum); } public static void main (String[] args) { add(10 ,20 ); add(30 ,90 ); } }
什么时候有返回值,什么时候没有返回值? 看心情–》看需求
6.方法的定义需要注意什么? 1)形参列表要怎么写:定义几个参数,分别是什么类型的 —》不确定因素我们会当做方法的形参 2) 方法到底是否需要返回值 ,如果需要的话,返回值的类型是什么
7.方法的调用需要注意什么? 1)实际参数要怎么传入:传入几个参数,传入什么类型的 2) 方法是否有返回值需要接受
练习 【1】基本功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import java.util.Scanner;public class TestMethod03 { public static void main (String[] args) { Scanner sc = new Scanner (System.in); System.out.println("请你猜一个数:" ); int yourGuessNum = sc.nextInt(); int myHeartNum = 5 ; System.out.println(yourGuessNum==myHeartNum?"猜对了" :"猜错了" ); } }
对猜数功能提取为一个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import java.util.Scanner;public class TestMethod03 { public static void main (String[] args) { Scanner sc = new Scanner (System.in); System.out.println("请你猜一个数:" ); int yourGuessNum = sc.nextInt(); guessNum(yourGuessNum); } public static void guessNum (int yourNum) { int myHeartNum = (int )(Math.random()*6 )+1 ; System.out.println(yourNum==myHeartNum?"猜对了" :"猜错了" ); } }
面试题:两个数交换是否成功 【1】面试题:请问下面代码中两个数是否交换成功: public class TestM{ public static void main(String[] args){ int a=10; int b=20; System.out.println(“输出交换前的两个数:”+a+”—“+b); changeNum(a,b); System.out.println(“输出交换后的两个数:”+a+”—“+b); } public static void changeNum(int num1,int num2){ int t; t=num1; num1=num2; num2=t; } }
结果:没有交换成功:
原因:
方法的重载 【1】什么是方法的重载: 方法的重载是指一个类中可以定义多个方法名相同,但参数不同的方法。 调用时,会根据不同的参数自动匹配对应的方法。
注意本质:重载的方法,实际是完全不同的方法,只是名称相同而已!
【2】构成方法重载的条件: ❀不同的含义:形参类型、形参个数、形参顺序不同 ❀ 只有返回值不同不构成方法的重载 如:int a(String str){}与 void a(String str){}不构成方法重载 ❀ 只有形参的名称不同,不构成方法的重载 如:int a(String str){}与int a(String s){}不构成方法重载
【3】代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 public class TestMethod05 { public static void main (String[] args) { int sum = add(10 ,20 ); System.out.println(sum); System.out.println(add(20 ,40 ,80 )); System.out.println(add(30 ,60 ,90 ,120 )); System.out.println(add(9.8 ,4.7 )); } public static int add (int num1,int num2) { return num1+num2; } public static int add (int num1,int num2,int num3) { return num1+num2+num3; } public static int add (int num1,int num2,int num3,int num4) { return num1+num2+num3+num4; } public static double add (double num1,double num2) { return num1+num2; } }
总结: 1.方法的重载:在同一个类中,方法名相同,形参列表不同的多个方法,构成了方法的重载。 2.方法的重载只跟:方法名和形参列表有关,与修饰符,返回值类型无关。 3.注意:形参列表不同指的是什么? (1)个数不同 add() add(int num1) add(int num1,int num2) (2)顺序不同 add(int num1,double num2) add(double num1,int num2) (3)类型不同 add(int num1) add(double num1)
4.请问下面的方法是否构成了方法的重载? (1)add(int a) 和 add(int b) —>不构成,相当于方法的重复定义 (2)public static int add(int a) 和 public static void add(int b) —>不构成
第6章_数组 数组的引入 【1】习题引入:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import java.util.Scanner;public class TestArray01 { public static void main (String[] args) { int sum = 0 ; Scanner sc = new Scanner (System.in); for (int i=1 ;i<=10 ;i++){ System.out.print("请录入第" +i+"个学生的成绩:" ); int score = sc.nextInt(); sum += score; } System.out.println("十个学生的成绩之和为:" +sum); System.out.println("十个学生的成绩平均数为:" +sum/10 ); } }
缺点:就是不能求每个学生的成绩具体是多少
解决:将成绩进行存储 —-》 引入 : 数组
感受到数组的作用:数组用来存储数据的,在程序设计中,为了处理方便,数组用来将相同类型的若干数据组织起来。 这个若干数据的集合我们称之为数组。
数组的学习 【1】数组的定义 数组是相同类型数据的有序集合。数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。其中,每一个数据称作一个元素,每个元素可以通过一个索引(下标)来访问它们。 数组的四个基本特点: 1.长度是确定的。数组一旦被创建,它的大小就是不可以改变的。 2.其元素的类型必须是相同类型,不允许出现混合类型。 3.数组类型可以是任何数据类型,包括基本类型和引用类型。 4.数组有索引的:索引从0开始,到 数组.length-1 结束 5.数组变量属于引用类型,数组也是对象。 ==PS:数组变量属于引用类型,数组也是对象,数组中的每个元素相当于该对象的成员变量。数组本身就是对象,Java中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中存储的。==
【2】数组的学习:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 public class TestArray02 { public static void main (String[] args) { int [] arr; arr = new int [4 ]; arr[0 ] = 12 ; arr[3 ] = 47 ; arr[2 ] = 98 ; arr[1 ] = 56 ; arr[2 ] = 66 ; System.out.println(arr[2 ]); System.out.println(arr[0 ]+100 ); System.out.println("数组的长度是:" +arr.length); } }
内存分析
完善引入的习题_数组的遍历 【1】代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 import java.util.Scanner;public class TestArray03 { public static void main (String[] args) { int [] scores = new int [10 ]; int sum = 0 ; Scanner sc = new Scanner (System.in); for (int i=1 ;i<=10 ;i++){ System.out.print("请录入第" +i+"个学生的成绩:" ); int score = sc.nextInt(); scores[i-1 ] = score; sum += score; } System.out.println("十个学生的成绩之和为:" +sum); System.out.println("十个学生的成绩平均数为:" +sum/10 ); for (int i=0 ;i<=9 ;i++){ System.out.println("第" +(i+1 )+"个学生的成绩为:" +scores[i]); } int count = 0 ; for (int num:scores){ count++; System.out.println("第" +count+"个学生的成绩为:" +num); } for (int i=9 ;i>=0 ;i--){ System.out.println("第" +(i+1 )+"个学生的成绩为:" +scores[i]); } } }
【2】用IDEA验证数组的确将数据进行存储了:
数组的三种初始化方式 数组的初始化方式总共有三种:静态初始化、动态初始化、默认初始化。
静态初始化 除了用new关键字来产生数组以外,还可以直接在定义数组的同时就为数组元素分配空间并赋值。
eg: int[] arr = {12,23,45}; int[] arr = new int[]{12,23,45}; 注意: 1.new int[3]{12,23,45};–>错误 2.int[] arr ; arr = {12,23,45}; —>错误
动态初始化 数组定义与为数组元素分配空间并赋值的操作分开进行。
eg: int[] arr ; arr = new int[3] arr[0] = 12; arr[1] = 23; arr[2] = 45;
默认初始化 数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化。
int[] arr = new int[3]; —> 数组有默认的初始化值
数组的应用题 最值问题 【1】实现一个功能:给定一个数组int[] arr = {12,3,7,4,8,125,9,45}; ,求出数组中最大的数。 思路图:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class TestArray04 { public static void main (String[] args) { int [] arr = {12 ,3 ,7 ,4 ,8 ,125 ,9 ,45 ,666 ,36 }; int maxNum = arr[0 ]; for (int i=0 ;i<arr.length;i++){ if (arr[i]>maxNum){ maxNum = arr[i]; } } System.out.println("当前数组中最大的数为:" +maxNum); } }
【2】将求最大值的方法提取出来:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public class TestArray04 { public static void main (String[] args) { int [] arr = {12 ,3 ,7 ,4 ,8 ,725 ,9 ,45 ,666 ,36 }; int num = getMaxNum(arr); System.out.println("当前数组中最大的数为:" +num); } public static int getMaxNum (int [] arr) { int maxNum = arr[0 ]; for (int i=0 ;i<arr.length;i++){ if (arr[i]>maxNum){ maxNum = arr[i]; } } return maxNum; } }
【3】画内存: ==方法的实参传递给形参的时候一定要注意:一切都是值传递:== ==如果是基本数据类型,那么传递的就是字面值== ==如果是引用数据类型,那么传递的就是地址值==
查询问题 【1】查询指定位置的元素
1 2 3 4 5 6 7 8 9 public class TestArray05 { public static void main (String[] args) { int [] arr = {12 ,34 ,56 ,7 ,3 ,10 }; System.out.println(arr[2 ]); } }
上面代码体现了数组的一个优点: 在按照位置查询的时候,直接一步到位,效率非常高
【2】查询指定元素的位置–》找出元素对应的索引
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class TestArray06 { public static void main (String[] args) { int [] arr = {12 ,34 ,56 ,7 ,3 ,56 }; int index = -1 ; for (int i=0 ;i<arr.length;i++){ if (arr[i]==12 ){ index = i; break ; } } if (index!=-1 ){ System.out.println("元素对应的索引:" +index); }else { System.out.println("查无次数!" ); } } }
【3】将查指定元素对应的索引的功能提取为方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 public class TestArray06 { public static void main (String[] args) { int [] arr = {12 ,34 ,56 ,7 ,3 ,56 }; int index = getIndex(arr,999 ); if (index!=-1 ){ System.out.println("元素对应的索引:" +index); }else { System.out.println("查无次数!" ); } } public static int getIndex (int [] arr,int ele) { int index = -1 ; for (int i=0 ;i<arr.length;i++){ if (arr[i]==ele){ index = i; break ; } } return index; } }
添加元素 【1】实现一个功能: 添加逻辑:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public class TestArray07 { public static void main (String[] args) { int [] arr = {12 ,34 ,56 ,7 ,3 ,10 ,55 ,66 ,77 ,88 ,999 ,89 }; System.out.print("增加元素前的数组:" ); for (int i=0 ;i<arr.length;i++){ if (i!=arr.length-1 ){ System.out.print(arr[i]+"," ); }else { System.out.print(arr[i]); } } int index = 1 ; for (int i=arr.length-1 ;i>=(index+1 );i--){ arr[i] = arr[i-1 ]; } arr[index] = 666 ; System.out.print("\n增加元素后的数组:" ); for (int i=0 ;i<arr.length;i++){ if (i!=arr.length-1 ){ System.out.print(arr[i]+"," ); }else { System.out.print(arr[i]); } } } }
【2】将添加功能提取为一个 方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 import java.util.Scanner;public class TestArray07 { public static void main (String[] args) { int [] arr = {12 ,34 ,56 ,7 ,3 ,10 ,55 ,66 ,77 ,88 ,999 ,89 }; Scanner sc = new Scanner (System.in); System.out.println("请录入你要添加元素的指定下标:" ); int index = sc.nextInt(); System.out.println("请录入你要添加的元素:" ); int ele = sc.nextInt(); insertEle(arr,index,ele); System.out.print("\n增加元素后的数组:" ); for (int i=0 ;i<arr.length;i++){ if (i!=arr.length-1 ){ System.out.print(arr[i]+"," ); }else { System.out.print(arr[i]); } } } public static void insertEle (int [] arr,int index,int ele) { for (int i=arr.length-1 ;i>=(index+1 );i--){ arr[i] = arr[i-1 ]; } arr[index] = ele; } }
删除元素 【1】实现一个功能:删除指定位置上的元素 逻辑:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import java.util.Arrays;public class TestArray08 { public static void main (String[] args) { int [] arr = {12 ,34 ,56 ,7 ,3 ,10 ,34 ,45 ,56 ,7 ,666 }; System.out.println("删除元素前的数组:" +Arrays.toString(arr)); int index = 0 ; for (int i=index;i<=arr.length-2 ;i++){ arr[i] = arr[i+1 ]; } arr[arr.length-1 ] = 0 ; System.out.println("删除元素后的数组:" +Arrays.toString(arr)); } }
【2】实现一个功能:删除指定元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 import java.util.Arrays;public class TestArray09 { public static void main (String[] args) { int [] arr = {12 ,34 ,56 ,7 ,3 ,10 ,34 ,45 ,56 ,7 ,666 }; System.out.println("删除元素前的数组:" +Arrays.toString(arr)); int index = -1 ; for (int i=0 ;i<arr.length;i++){ if (arr[i]==1200 ){ index = i; break ; } } if (index!=-1 ){ for (int i=index;i<=arr.length-2 ;i++){ arr[i] = arr[i+1 ]; } arr[arr.length-1 ] = 0 ; }else { System.out.println("根本没有你要删除的元素!" ); } System.out.println("删除元素后的数组:" +Arrays.toString(arr)); } }
详述main方法 【1】main方法:程序的入口,在同一个类中,如果有多个方法,那么虚拟机就会识别main方法,从这个方法作为程序的入口 【2】main方法格式严格要求: public static void main(String[] args){}
public static —>修饰符 ,暂时用这个 –>面向对象一章 void —>代表方法没有返回值 对应的类型void main —>见名知意名字 String[] args —>形参 —》不确定因素
【3】问题:程序中是否可以有其他的方法也叫main方法? 可以,构成了方法的重载。
1 2 3 4 5 6 7 8 public class TestArray10 { public static void main (String[] args) { } public static void main (String str) { } }
【4】形参为String[] 那么实参到底是什么?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class TestArray10 { public static void main (String[] args) { System.out.println(args.length); for (String str:args){ System.out.println(str); } } }
手动传入实参: 有特殊符号的时候可以加上“”
没有特殊符号用空格隔开即可:
可变参数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class TestArray12 { public static void main (String[] args) { method01(30 ,40 ,50 ,60 ,70 ); } public static void method01 (int num2,int ...num) { System.out.println("-----1" ); for (int i:num){ System.out.print(i+"\t" ); } System.out.println(); System.out.println(num2); } }
Arrays工具类 为了方便我们对数组进行操作,系统提供一个类Arrays,我们将它当做工具类来使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 import java.util.Arrays;public class TestArray13 { public static void main (String[] args) { int [] arr = {1 ,3 ,7 ,2 ,4 ,8 }; System.out.println(Arrays.toString(arr)); Arrays.sort(arr); System.out.println(Arrays.toString(arr)); System.out.println(Arrays.binarySearch(arr,4 )); int [] arr2 = {1 ,3 ,7 ,2 ,4 ,8 }; int [] newArr = Arrays.copyOf(arr2,4 ); System.out.println(Arrays.toString(newArr)); int [] newArr2 = Arrays.copyOfRange(arr2,1 ,4 ); System.out.println(Arrays.toString(newArr2)); int [] arr3 = {1 ,3 ,7 ,2 ,4 ,8 }; int [] arr4 = {1 ,3 ,7 ,2 ,4 ,8 }; System.out.println(Arrays.equals(arr3,arr4)); System.out.println(arr3==arr4); int [] arr5 = {1 ,3 ,7 ,2 ,4 ,8 }; Arrays.fill(arr5,10 ); System.out.println(Arrays.toString(arr5)); } }
数组的复制操作
原理:
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import java.util.Arrays;public class TestArray14 { public static void main (String[] args) { int [] srcArr = {11 ,22 ,33 ,44 ,55 ,66 ,77 ,88 }; int [] destArr = new int [10 ]; System.arraycopy(srcArr,1 ,destArr,3 ,3 ); System.out.println(Arrays.toString(destArr)); } }
结果:
二维数组 【1】引入:本质上全部都是一维数组:
【2】基本代码
1 2 3 4 5 6 7 8 9 10 11 12 13 public class TestArray15 { public static void main (String[] args) { int [][] arr = new int [3 ][]; int [] a1 = {1 ,2 ,3 }; arr[0 ] = a1; arr[1 ] = new int []{4 ,5 ,6 ,7 }; arr[2 ] = new int []{9 ,10 }; } }
对应内存:
【3】四种遍历方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 public class TestArray15 { public static void main (String[] args) { int [][] arr = new int [3 ][]; int [] a1 = {1 ,2 ,3 }; arr[0 ] = a1; arr[1 ] = new int []{4 ,5 ,6 ,7 }; arr[2 ] = new int []{9 ,10 }; for (int i=0 ;i<arr.length;i++){ for (int j=0 ;j<arr[i].length;j++){ System.out.print(arr[i][j]+"\t" ); } System.out.println(); } for (int i=0 ;i<arr.length;i++){ for (int num:arr[i]){ System.out.print(num+"\t" ); } System.out.println(); } for (int [] a:arr){ for (int num:a){ System.out.print(num+"\t" ); } System.out.println(); } for (int [] a:arr){ for (int i=0 ;i<a.length;i++){ System.out.print(a[i]+"\t" ); } System.out.println(); } } }
二维数组的初始化方式 数组的初始化方式总共有三种:静态初始化、动态初始化、默认初始化。
静态初始化 除了用new关键字来产生数组以外,还可以直接在定义数组的同时就为数组元素分配空间并赋值。
eg:
1 2 int [][] arr = {{1 ,2 },{4 ,5 ,6 },{4 ,5 ,6 ,7 ,8 ,9 ,9 }};int [][] arr =new int [][] {{1 ,2 },{4 ,5 ,6 },{4 ,5 ,6 ,7 ,8 ,9 ,9 }};
动态初始化 数组定义与为数组元素分配空间并赋值的操作分开进行。 eg: int[][] arr = new int[3][]; //本质上定义了一维数组长度为3,每个“格子”中放入的是一个数组 arr[0] = new int[]{1,2}; arr[1] = new int[]{3,4,5,6}; arr[2] = new int[]{34,45,56};
eg:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 int [][] arr = new int [3 ][2 ]; public class TestArray16 { public static void main (String[] args) { int [][] arr = new int [3 ][2 ]; arr[1 ] = new int []{1 ,2 ,3 ,4 }; for (int [] a:arr){ for (int num:a){ System.out.print(num+"\t" ); } System.out.println(); } } }
默认初始化 数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化。
第7章_IDEA的使用 IDEA IDE 集成开发环境(IDE,Integrated Development Environment )是用于提供程序开发环境的应用程序,一般包括代码编辑器、编译器、调试器和图形用户界面等工具。集成了代码编写功能、分析功能、编译功能、调试功能等一体化的开发软件服务套。所有具备这一特性的软件或者软件套(组)都可以叫集成开发环境。如微软的Visual Studio系列,Borland的C++ Builder、Delphi系列等。该程序可以独立运行,也可以和其它程序并用。IDE多被用于开发HTML应用软件。例如,许多人在设计网站时使用IDE(如HomeSite、DreamWeaver等),因为很多项任务会自动生成。编程开发软件将编辑、编译、调试等功能集成在一个桌面环境中,这样就大大方便了用户。
❀优点 节省时间和精力。IDE的目的就是要让开发更加快捷方便,通过提供工具和各种性能来帮助开发者组织资源,减少失误,提供捷径。 建立统一标准。当一组程序员使用同一个开发环境时,就建立了统一的工作标准,当IDE提供预设的模板,或者不同团队分享代码库时,这一效果就更加明显了。 管理开发工作。首先,IDE提供文档工具,可以自动输入开发者评论,或者迫使开发者在不同区域编写评论。其次,IDE可以展示资源,更便于发现应用所处位置,无需在文件系统里面艰难的搜索。
❀缺点 学习曲线问题。IDE基本上是比较复杂的工具,为了更好的熟练使用,需要一定的时间和耐心。 初学者的困难。对初学者来说,使用IDE来学习开发有相当的难度,不适合学习一种新语言时使用。 无法修复坏代码或设计。开发者不能完全依赖工具的便捷,还是必须保持专业水准和熟练度,开发的成果好坏主要还是看开发员的技术。
JetBrains公司介绍 【1】IntelliJ IDEA就是Java的IDE。 【2】市场占有率竹节攀升,超过了Eclipse。 【3】JetBrains公司介绍: JetBrains是一家捷克的软件开发公司,该公司位于捷克的布拉格,并在俄罗斯的圣彼得堡及美国麻州波士顿都设有办公室,该公司最为人所熟知的产品是Java编程语言开发撰写时所用的集成开发环境:IntelliJ IDEA。公司旗下还有其它产品,比如: ➢WebStorm: 用于开发JavaScript、HTML5、 CS3等前端技术; ➢PyCharm: 用于开发python(python语言热度排行榜排名第一,在人工智能大数据领域应用) ➢PhpStorm: 用于开发PHP ➢RubyMine: 用于开发Ruby/Rails ➢AppCode: 用于开发Objective - C/Swift,替换xcode的 ➢CLion: 用于开发C/C++ ➢DataGrip: 用于开发数据库和SQL ➢Rider: 用于开发.NET ➢GoLand: 用于开发Go(区块链主流开发语言就是Go语言)
【4】官网:https://www.jetbrains.com/
IntelliJ_IDEA介绍 【1】IDEA 全称IntelliJ IDEA,是用于java语言开发的集成环境IDE(Integrated Development Environment),也可用于其他语言。 IntelliJ在业界被公认为最好的java开发工具之一,尤其在智能代码助手、代码自动提示、重构、J2EE支持、Ant、JUnit、CVS整合、代码审查、 创新的GUI设计等方面的功能可以说是超常的。
IDEA是JetBrains公司的产品,这家公司总部位于捷克共和国的首都布拉格,开发人员以严谨著称的东欧程序员为主。
【2】IDEA的支持:
【3】IDEA的优势(相对于Eclipse) ①强大的整合能力。比如: Git、 Maven、 Spring 等 ②提示功能的快速、便捷 ③提示功能的范围广 ④好用的快捷键和代码模板 ⑤精准搜索
IntelliJ_IDEA的下载和安装的准备 【1】官网:https://www.jetbrains.com/idea/download/#section=windows
【2】安装的准备: (1)硬件环境: 内存8G以上 CPU i5以上 安装在固态硬盘下 (2)软件环境: 需要安装JDK
IDEA的卸载 对于免安装的idea: (1)删除安装文件 (2)到用户下将idea的缓存,配置的目录删除掉即可
安装idea: (1)可以用控制面板–》程序
IDEA的使用 对于免安装的idea: (1)删除安装文件 (2)到用户下将idea的缓存,配置的目录删除掉即可
安装idea: (1)可以用控制面板–》程序
选择主题:
创建一个项目:
IDEA页面展示 【1】项目下内容: ➢工程下的src类似于Eclipse下的src目录,用于存放代码。。 ➢工程下的.idea 和TestProject.iml文件都是IDEA工程特有的。类似于Eclipse 工程下的settings、.classpath、.project 等。 【2】配置:
Module的概念和使用 【1】在Eclipse中我们有Workspace (工作空间)和Project (工程)的概念,在IDEA中只有Project (工程)和Module (模块)的概念。 这里的对应关系为: IDEA官网说明: An Eclipse workspace is similar to a project in IntelliJ IDEA An Eclipse project maps to a module in IntelliJ IDEA 翻译: Eclipse中 workspace 相当于 IDEA中的Project Eclipse中 Project 相当于 IDEA中的Module
在IntelliJ IDEA中Project(工程) 是最顶级的级别,次级别是Module(模块)。 一个Project下可以有多个Module。
【2】从Eclipse 转过来的人总是下意识地要在同一个窗口管理n个项目,这在Intellij IDEA是无法做到的。Intellij IDEA提供的解决方案是打开多个项目实例,即打开多个项目窗口。即:一个Project 打开一个Window窗口。
【3】IDEA这样设置的原因: 目前主流的大型项目都是分布式部署的,结构都是类似这种多Module的。 这类项目一般是这样划分的,比如: 积分模块、任务模块、活动模块等等,模块之间彼此可以相互依赖。这些Module之间都是处于同一个项目业务下的模块,彼此之间是有不可分割的业务关系的。
【4】out目录的说明:里面存放的是编译后的字节码文件
【5】删除模块:
IDEA的常用设置 【1】进入设置:
【2】设置主题:
【3】编辑区的字体变大或者变小:
【4】鼠标悬浮在代码上有提示:
【5】自动导包和优化多余的包: 手动导包:快捷键:alt+enter 自动导包和优化多余的包:
【6】同一个包下的类,超过指定个数的时候,导包合并为*
【7】显示行号 , 方法和方法间的分隔符:
【8】忽略大小写,进行提示:
【9】多个类不隐藏,多行显示:
【10】设置默认的字体,字体大小,字体行间距:(编辑区和控制台都会变化)
【11】修改代码中注释的字体颜色:
【12】修改类头的文档注释信息:—》注意:对新建的类才有效 /**
@Auther: zhaoss @Date: ${DATE} - ${MONTH} - ${DAY} - ${TIME} @Description: ${PACKAGE_NAME} @version: 1.0 */
【13】设置项目文件编码:
文件右下角可以调节编码格式:
【14】自动编译:
【15】省电模式:
【16】代码显示结构:
【17】导入jar包:
【18】生成序列化版本号:
IDEA的常用快捷键 【1】创建内容:alt+insert 【2】main方法:psvm 【3】输出语句:sout 【4】复制行:ctrl+d 【5】删除行:ctrl+y
【6】代码向上/下移动:Ctrl + Shift + Up / Down 【7】搜索类: ctrl+n 【8】生成代码 :alt + Insert(如构造函数等,getter,setter,hashCode,equals,toString) 【9】百能快捷键 : alt + Enter (导包,生成变量等) 【10】单行注释或多行注释 : Ctrl + / 或 Ctrl + Shift + / 【11】重命名 shift+f6 【12】for循环 直接 :fori 回车即可 【13】代码块包围:try-catch,if,while等 ctrl+alt+t 【14】 代码自动补全提示:
【15】 idea代码字体大小放大和缩小的快捷键
【16】代码一层一层调用的快捷键: 点进源码:ctrl+鼠标悬浮在代码上+点进去即可:
【17】显示代码结构 : alt + 7 【18】显示导航栏: alt +1 【19】撤回:ctrl+z 【20】REDO操作: 如果跟搜狗输入法的快捷键冲突,可以选择将搜狗的快捷键取消。
【21】缩进:tab 取消缩进: shift+tab
模板的使用 代码模板是什么
它的原理就是配置一些==常用代码字母缩写==,在输入简写时可以出现你预定义的固定模式的代码,使得开发效率大大提高,同时也可以增加个性化。最简单的例子就是在Java中输入sout会出现System.out.println();
(一)所处位置: (1)Live Templates (2)Postfix Completion
(二)区别: 【1】 Live Templates中可以做用户的个性化定制。 Postfix Completion中只能用,不能修改。 【2】使用方式不同
修改现有模板 【1】案例1:改main方法: psvm
【2】案例2:修饰属性的修饰符:
常用的代码模板 【1】模板1: main方法: main 或者 psvm
【2】模板2:输出语句: sout 或者 .sout 一些变型: soutp:打印方法的形参 soutm:打印方法的名字 soutv:打印变量
【3】模板3: 循环 普通for循环: fori(正向) 或者 .fori (正向) . forr(逆向) 增强for循环: iter 或者 .for (可以用于数组的遍历,集合的遍历)
【4】模板4: 条件判断 ifn 或者 .null :判断是否为null (if null) inn 或者 .nn :判断不等于null (if not null)
【5】模板5: 属性修饰符: prsf : private static final psf :public static final
自定义模板 【1】测试方法:
【2】常用属性:($$中的内容其实就是在定义光标的位置,光标可以切换,用回车切换)
【3】方法注释模板: /**
功能描述: @param: $param$ @return: $return$ @auther: $user$ @date: $date$ $time$ */
IDEA中的断点调试 常用断点调试快捷键
调试在开发中大量应用: 【1】Debug的优化设置:更加节省内存空间: 设置Debug连接方式,默认是Socket。 Shared memory是Windows 特有的一个属性,一般在Windows系统下建议使用此设置, 内存占用相对较少。
【2】常用断点调试快捷键:
条件判断,查看表达式的值
【1】条件判断: 说明: 调试的时候,在循环里增加条件判断,可以极大的提高效率,心情也能惧悦。 具体操作: 在断点处右击调出条件断点。可以在满足某个条件下,实施断点。
【2】查看表达式的值: 选择行,alt+f8。
第8章_面向对象 面向过程和面向对象的区别 面向过程:当事件比较简单的时候,利用面向过程,注重的是事件的具体的步骤/过程,注重的是过程中的具体的行为,以函数为最小单位,考虑怎么做。
面向对象:注重找“参与者”,将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。
案例: 人把大象装进冰箱: 面向过程: 函数1:打开冰箱(){人站在冰箱前,打开冰箱,冰箱卡到30度角的时候,冰箱的灯打开了………} 函数2:储存大象(){大象先迈左腿,再迈右退,考虑冰箱能不能装下……} 函数3:关闭冰箱(){人站在冰箱前,关闭冰箱,冰箱开到30度角的时候,冰箱的灯关闭了……….}
面向对象: 人{ 打开(冰箱){ 冰箱.打开(); } 存储(大象){ 大象.进入(); }
关闭(冰箱){ 冰箱.关闭(); }
}
冰箱{
打开(){ 1.2.3.}
关闭(){}
}
柜子{
}
大象{ 进入(冰箱){
}
}
面向过程 —> 面向对象 , 其实就是由执行者 —> 指挥者的 一个过渡
面向过程:编年体 面向对象:纪传体
二者相辅相成,并不是对立的。解决复杂问题,通过面向对象方式便于我们从宏观上把握事物之间复杂的关系、方便我们分析整个系统;具体到微观操作,仍然使用面向过程方式来处理
类和对象的关系 【1】万事万物皆对象
【2】 对象:具体的事物,具体的实体,具体的实例,模板下具体的产品 类:对对象向上抽取出像的部分,公共的部分,形成类,类是抽象的,是一个模板
【3】一般在写代码的时候先写类,然后在根据类创建对应的对象。
面向对象三个阶段 面向对象三个阶段: 【1】面向对象分析OOA – Object Oriented Analysis 对象:张三,王五,朱六,你,我 抽取出一个类—-》人类
类里面有什么: 动词–》动态特性–》方法 名词–》静态特性–》属性 【2】面向对象设计OOD – Object Oriented Design 先有类,再有对象: 类:人类: Person 对象:zhangsan ,lisi,zhuliu 【3】面向对象编程OOP – Object Oriented Programming
创建类 创建类: (1)属性(field 成员变量) 属性用于定义该类或该类对象包含的数据或者说静态特征。属性作用范围是整个类体。 属性定义格式: [修饰符] 属性类型 属性名 = [默认值] ;
(2)方法 方法用于定义该类或该类实例的行为特征和功能实现。方法是类和对象行为特征的抽象。方法很类似于面向过程中的函数。面向过程中,函数是最基本单位,整个程序由一个个函数调用组成。面向对象中,整个程序的基本单位是类,方法是从属于类和对象的。 方法定义格式: [修饰符] 方法返回值类型 方法名(形参列表) { // n条语句 } void代表没有返回值;方法的作用:重用代码,封装功能,便于修改
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package com.msb;public class Person { int age ; String name; double height; double weight; public void eat () { int num = 10 ; System.out.println("我喜欢吃饭" ); } public void sleep (String address) { System.out.println("我在" +address+"睡觉" ); } public String introduce () { return "我的名字是:" +name+",我的年龄是:" +age+",我的身高是:" +height+",我的体重是:" +weight; } }
创建对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 package com.msb;public class Test { public static void main (String[] args) { Person zs = new Person (); zs.name = "张三" ; zs.age = 19 ; zs.height = 180.4 ; zs.weight = 170.4 ; Person ls = new Person (); ls.name = "李四" ; ls.age = 18 ; ls.height = 170.6 ; ls.weight = 160.5 ; System.out.println(zs.name); System.out.println(ls.age); zs.eat(); ls.eat(); zs.sleep("教室" ); System.out.println(zs.introduce()); } }
局部变量和成员变量的区别 区别1 :代码中位置不同 成员变量:类中方法外定义的变量 局部变量:方法中定义的变量 代码块中定义的变量区别2 :代码的作用范围 成员变量:当前类的很多方法 局部变量:当前一个方法(当前代码块)
区别3 :是否有默认值 成员变量:有 局部变量:没有
引用数据类型: null区别4 :是否要初始化 成员变量:不需要,不建议初始化,后续使用的时候再赋值即可 局部变量:一定需要,不然直接使用的时候报错
区别5 :内存中位置不同 成员变量:堆内存 局部变量:栈内存区别6 :作用时间不同 成员变量:当前对象从创建到销毁 局部变量:当前方法从开始执行到执行完毕
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 package com.msb;public class Student { byte e; short s; int c ; long num2; float f ; double d; char ch; boolean bo; String name; public void study () { int num = 10 ; System.out.println(num); { int a; } int a; if (1 ==3 ){ int b; } System.out.println(c); } public void eat () { System.out.println(c); } public static void main (String[] args) { Student s = new Student (); System.out.println(s.c); System.out.println(s.bo); System.out.println(s.ch); System.out.println(s.d); System.out.println(s.e); System.out.println(s.f); System.out.println(s.name); System.out.println(s.num2); System.out.println(s.s); s.d = 10.4 ; } }
运行结果:
构造器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package com.msb2;public class Person { public Person () { } String name; int age; double height; public void eat () { System.out.println("我喜欢吃饭" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 package com.msb2;public class Test { public static void main (String[] args) { Person p = new Person (); System.out.println(p.age); System.out.println(p.name); System.out.println(p.height); Person p2 = new Person (); System.out.println(p2.age); System.out.println(p2.name); System.out.println(p2.height); } }
构造器的重载 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package com.msb3.msb2;public class Person { String name; int age; double height; public Person () { } public Person (String name,int age,double height) { this .name = name; this .age = age; this .height = height; } public Person (String a,int b) { name = a; age = b; } public void eat () { System.out.println("我喜欢吃饭" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package com.msb3.msb2;public class Test { public static void main (String[] args) { Person p = new Person (); Person p2 = new Person ("lili" ,19 ,180.4 ); System.out.println(p2.age); System.out.println(p2.height); System.out.println(p2.name); } }
内存分析 this 【1】创建对象的过程: (1)在第一次遇到一个类的时候,对这个类要进行加载,只加载一次。 (2)创建对象,在堆中开辟空间 (3)对对象进行初始化操作,属性赋值都是默认的初始值。 (4)new关键字调用构造器,执行构造方法,在构造器中对属性重新进行赋值
this:
从上面的效果能够看到:this指代的就是当前对象:
内存:
this关键字 用法: ==(1)this可以修饰属性:== 总结:当属性名字和形参发生重名的时候,或者 属性名字 和局部变量重名的时候,都会发生就近原则,所以如果我要是直接使用变量名字的话就指的是离的近的那个形参或者局部变量,这时候如果我想要表示属性的话,在前面要加上:this.修饰
如果不发生重名问题的话,实际上你要是访问属性也可以省略this.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package com.msb4;public class Person { int age; String name; double height; public Person () { } public Person (int age,String name,double height) { this .age = age; this .name = name; this .height = height; } public void eat () { int age = 10 ; System.out.println(age); System.out.println(this .age); System.out.println("我喜欢吃饭" ); } }
==(2)this修饰方法:== 总结:在同一个类中,方法可以互相调用,this.可以省略不写。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 package com.msb4;public class Person { int age; String name; double height; public Person () { } public Person (int age,String name,double height) { this .age = age; this .name = name; this .height = height; } public void play () { eat(); System.out.println("上网" ); System.out.println("洗澡" ); } public void eat () { System.out.println(age); System.out.println("吃饭" ); } }
==(3)this可以修饰构造器:== 总结:同一个类中的构造器可以相互用this调用,注意:this修饰构造器必须放在第一行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 package com.msb4;public class Person { int age; String name; double height; public Person () { } public Person (int age,String name,double height) { this (age,name); this .height = height; } public Person (int age,String name) { this (age); this .name = name; } public Person (int age) { this .age = age; } public void play () { eat(); System.out.println("上网" ); System.out.println("洗澡" ); } public void eat () { System.out.println(age); System.out.println("吃饭" ); } }
static 【1】static可以修饰:属性,方法,代码块,内部类。
【2】static修饰属性;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package com.msb5;public class Test { int id; static int sid; public static void main (String[] args) { Test t1 = new Test (); t1.id = 10 ; t1.sid = 10 ; Test t2 = new Test (); t2.id = 20 ; t2.sid = 20 ; Test t3 = new Test (); t3.id = 30 ; t3.sid = 30 ; System.out.println(t1.id); System.out.println(t2.id); System.out.println(t3.id); System.out.println(t1.sid); System.out.println(t2.sid); System.out.println(t3.sid); } }
内存分析:
一般官方的推荐访问方式:可以通过类名.属性名的方式去访问:
static修饰属性总结: (1)在类加载的时候一起加载入方法区中的静态域中 (2)先于对象存在 (3)访问方式: 对象名.属性名 类名.属性名(推荐)
static修饰属性的应用场景:某些特定的数据想要在内存中共享,只有一块 –》这个情况下,就可以用static修饰的属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package com.msb5;public class MsbStudent { String name; int age; static String school; public static void main (String[] args) { MsbStudent.school = "马士兵教育" ; MsbStudent s1 = new MsbStudent (); s1.name = "张三" ; s1.age = 19 ; MsbStudent s2 = new MsbStudent (); s2.name = "李四" ; s2.age = 21 ; System.out.println(s2.school); } }
属性: 静态属性 (类变量) 非静态属性(实例变量)
【3】static修饰方法;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 package com.msb5;public class Demo { int id; static int sid; public void a () { System.out.println(id); System.out.println(sid); System.out.println("------a" ); } static public void b () { System.out.println(sid); System.out.println("------b" ); } public static void main (String[] args) { Demo d = new Demo (); d.a(); Demo.b(); d.b(); } }
代码块 【1】类的组成:属性,方法,构造器,代码块,内部类 【2】代码块分类:普通块,构造块,静态块,同步块(多线程) 【3】代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 package com.msb6;public class Test { int a; static int sa; public void a () { System.out.println("-----a" ); { System.out.println("这是普通块" ); System.out.println("----000000" ); int num = 10 ; System.out.println(num); } } public static void b () { System.out.println("------b" ); } { System.out.println("------这是构造块" ); } static { System.out.println("-----这是静态块" ); System.out.println(sa); b(); } public Test () { System.out.println("这是空构造器" ); } public Test (int a) { this .a = a; } public static void main (String[] args) { Test t = new Test (); t.a(); Test t2 = new Test (); t2.a(); } }
总结: (1)代码块执行顺序: 最先执行静态块,只在类加载的时候执行一次,所以一般以后实战写项目:创建工厂,数据库的初始化信息都放入静态块。 一般用于执行一些全局性的初始化操作。
再执行构造块,(不常用) 再执行构造器, 再执行方法中的普通块。
包,import 【1】生活案例: 邮寄快递:中国.北京.通州区.****小区.5号楼.3单元.101房.赵珊珊 历史:常山赵子龙
【2】包的作用: 为了解决重名问题(实际上包对应的就是盘符上的目录) 解决权限问题
【3】创建包:
包名定义: (1)名字全部小写 (2)中间用.隔开 (3)一般都是公司域名倒着写 : com.jd com.msb (4)加上模块名字: com.jd.login com.jd.register (5)不能使用系统中的关键字:nul,con,com1—com9….. (6)包声明的位置一般都在非注释性代码的第一行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package com.msb7;import com.msb2.Person; import java.util.Date;public class Test { public static void main (String[] args) { new Person (); new Date (); new java .sql.Date(1000L ); new Demo (); } }
总结: (1)使用不同包下的类要需要导包: import **.. ; 例如:import java.util.Date; (2)在导包以后,还想用其他包下同名的类,就必须要手动自己写所在的包。 (3)同一个包下的类想使用不需要导包,可以直接使用。 (4)在java.lang包下的类,可以直接使用无需导包:
(5)IDEA中导包快捷键:alt+enter 可以自己设置自动导包
(6)可以直接导入*:
【5】在Java中的导包没有包含和被包含的关系: 设置目录平级的格式(不是包含和被包含的显示):
【6】静态导入:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package com.msb11;import static java.lang.Math.*;public class Test { public static void main (String[] args) { System.out.println(random()); System.out.println(PI); System.out.println(round(5.6 )); } public static int round (double a) { return 1000 ; } }
三大特性 封装(Encapsulation)、 【1】生活案例: ATM , 电线 【2】Java中封装的理解: 将某些东西进行隐藏,然后提供相应的方式进行获取。
我们程序设计追求“高内聚,低耦合”。 ➢高内聚:类的内部数据操作细节自己完成,不允许外部干涉; ➢低耦合:仅对外暴露少量的方法用于使用。 隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提 高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露 的暴露出来。这就是封装性的设计思想。 【3】封装的好处: 提高代码的安全性
【4】代码:通过一个属性感受封装:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package com.msb.test01;public class Girl { private int age; public int duquAge () { return age; } public void shezhiAge (int age) { if (age >= 30 ){ this .age = 18 ; }else { this .age = age; } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package com.msb.test01;public class Test { public static void main (String[] args) { Girl g = new Girl (); g.shezhiAge(31 ); System.out.println(g.duquAge()); } }
上面的代码,对于属性age来说,我加了修饰符private,这样外界对它的访问就受到了限制,现在我还想加上其他的限制条件,但是在属性本身上没有办法再加了,所以我们通过定义方法来进行限制条件的添加。 以属性为案例: 进行封装: (1)将属性私有化,被private修饰–》加入权限修饰符 一旦加入了权限修饰符,其他人就不可以随意的获取这个属性 (2)提供public修饰的方法让别人来访问/使用 (3)即使外界可以通过方法来访问属性了,但是也不能随意访问,因为咱们在方法中可以加入 限制条件。
【5】实际开发中,方法一般会写成 setter,getter方法: 可以利用IDEA快捷键生成:alt+insert –>getter and setter:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class Girl { private int age; public int getAge () { return age; } public void setAge (int age) { if (age >= 30 ){ this .age = 18 ; }else { this .age = age; } } }
【6】加深练习:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 package com.msb.test2;public class Student { private int age; private String name; private String sex; public int getAge () { return age; } public void setAge (int age) { this .age = age; } public String getName () { return name; } public void setName (String name) { this .name = name; } public String getSex () { return sex; } public void setSex (String sex) { if ("男" .equals(sex) || "女" .equals(sex) ){ this .sex = sex; }else { this .sex = "男" ; } } public Student () { } public Student (int age,String name,String sex) { this .age = age; this .name = name; this .setSex(sex); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package com.msb.test2;public class Test { public static void main (String[] args) { Student s1 = new Student (); s1.setName("nana" ); s1.setAge(19 ); s1.setSex("女" ); System.out.println(s1.getName()+"---" +s1.getAge()+"----" +s1.getSex()); Student s2 = new Student (18 ,"菲菲" ,"asdfasdfsadf" ); System.out.println(s2.getName()+"---" +s2.getAge()+"----" +s2.getSex()); } }
继承(Inheritance) 【1】类是对对象的抽象: 举例: 荣耀20 ,小米 红米3,华为 p40 pro —> 类:手机类
【2】继承是对类的抽象: 举例: 学生类:Student: 属性:姓名,年龄,身高,学生编号 方法:吃饭,睡觉,喊叫,学习
教师类:Teacher: 属性:姓名,年龄,身高,教师编号 方法:吃饭,睡觉,喊叫,教学
员工类:Emploee: 属性:姓名,年龄,身高,员工编号 方法:吃饭,睡觉,喊叫,工作
共同的东西: 人类: 属性:姓名,年龄,身高 方法:吃饭,睡觉,喊叫
学生类/教师类/员工类 继承 自 人类
以后定义代码: 先定义人类: 人类: —》父类,基类,超类 属性:姓名,年龄,身高 方法:吃饭,睡觉,喊叫
再定义 : —》子类,派生类
学生类:Student: 属性:学生编号 方法:学习
教师类:Teacher: 属性:教师编号 方法:教学
员工类:Emploee: 属性:员工编号 方法:工作
子类 继承自 父类
狗类: 属性:姓名,年龄,身高 方法:吃饭,睡觉,喊叫
我们的继承关系,是在合理的范围中进行的抽取 ,抽取出子类父类的关系: 上面的案例中: 学生类/教师类/员工类 继承 自 人类 —》合理 学生类/教师类/员工类 继承 自 狗类 —》不合理
区分: 学生是一个人 教师是一个人 员工是一个人 —》合理
学生是一个狗 —》不合理
总结:继承 就是 is - a 的关系
【3】代码层面的解释: 先写父类,再写子类:
父类:人类 Person 子类:学生类 Student
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 package com.msb.test03;public class Person { private int age; private String name; private double height; public int getAge () { return age; } public void setAge (int age) { this .age = age; } public String getName () { return name; } public void setName (String name) { this .name = name; } public double getHeight () { return height; } public void setHeight (double height) { this .height = height; } public void eat () { System.out.println("可以吃饭。。。" ); } public void sleep () { System.out.println("可以睡觉。。。" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package com.msb.test03;public class Student extends Person { private int sno; public int getSno () { return sno; } public void setSno (int sno) { this .sno = sno; } public void study () { System.out.println("学生可以学习" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package com.msb.test03;public class Test { public static void main (String[] args) { Student s = new Student (); s.setSno(1001 ); s.setAge(18 ); s.setName("菲菲" ); s.setHeight(180.4 ); System.out.println("学生名字为:" +s.getName()+",学生的年纪:" +s.getAge()); s.study(); s.eat(); s.sleep(); } }
【4】继承的好处:提高代码的复用性 父类定义的内容,子类可以直接拿过来用就可以了,不用代码上反复重复定义了
需要注意的点: 父类private修饰的内容,子类实际上也继承,只是因为封装的特性阻碍了直接调用,但是提供了间接调用的方式,可以间接调用。
【5】总结:
(1)继承关系 : 父类/基类/超类 子类/派生类 子类继承父类一定在合理的范围进行继承的 子类 extends 父类 (2)继承的好处: 1.提高了代码的复用性,父类定义的内容,子类可以直接拿过来用就可以了,不用代码上反复重复定义了 2.便于代码的扩展 3.为了以后多态的使用。是多态的前提。
(3)父类private修饰的内容,子类也继承过来了。 (4)一个父类可以有多个子类。 (5)一个子类只能有一个直接父类。 但是可以间接的继承自其它类。
(6)继承具有传递性:
Student –》继承自 Person —》继承自Object Object类是所有类的根基父类。 所有的类都直接或者间接的继承自Object。
内存分析
权限修饰符
【1】private:权限:在当前类中可以访问
【2】default:缺省修饰符:权限:到同一个包下的其他类都可以访问
【3】protected:权限:最大到不同包下的子类
【4】public:在整个项目中都可以访问
总结: 属性,方法:修饰符:四种:private,缺省,protected,public 类:修饰符:两种:缺省,public
以后写代码 一般属性:用private修饰 ,方法:用public修饰
方法的重写 【1】重写: 发生在子类和父类中,当子类对父类提供的方法不满意的时候,要对父类的方法进行重写。
【2】重写有严格的格式要求: 子类的方法名字和父类必须一致,参数列表(个数,类型,顺序)也要和父类一致。
【3】代码:
1 2 3 4 5 6 7 8 9 public class Person { public void eat () { System.out.println("吃食物" ); } public void sleep () { System.out.println("睡觉" ); } }
1 2 3 4 5 6 7 8 9 public class Student extends Person { public void study () { System.out.println("学习" ); } @override public void eat () { System.out.println("我喜欢吃小龙虾喝啤酒。。" ); } }
1 2 3 4 5 6 7 8 public class Test { public static void main (String[] args) { Student s = new Student (); s.eat(); } }
【4】内存:
【5】重载和重写的区别: 重载:在同一个类中,当方法名相同,形参列表不同的时候 多个方法构成了重载 重写:在不同的类中,子类对父类提供的方法不满意的时候,要对父类的方法进行重写。
super 【1】super:指的是: 父类的 【2】super可以修饰属性,可以修饰方法;
在子类的方法中,可以通过 super.属性 super.方法 的方式,显示的去调用父类提供的属性,方法。在通常情况下,super.可以省略不写:
在特殊情况下,当子类和父类的属性重名时,你要想使用父类的属性,必须加上修饰符super.,只能通过super.属性来调用 在特殊情况下,当子类和父类的方法重名时,你要想使用父类的方法,必须加上修饰符super.,只能通过super.方法来调用 在这种情况下,super.就不可以省略不写。
【3】super修饰构造器: 其实我们平时写的构造器的第一行都有:super() –>作用:调用父类的空构造器,只是我们一般都省略不写 (所有构造器的第一行默认情况下都有super(),但是一旦你的构造器中显示的使用super调用了父类构造器,那么这个super()就不会给你默认分配了。如果构造器中没有显示的调用父类构造器的话,那么第一行都有super(),可以省略不写)
如果构造器中已经显示的调用super父类构造器,那么它的第一行就没有默认分配的super();了
在构造器中,super调用父类构造器和this调用子类构造器只能存在一个,两者不能共存: 因为super修饰构造器要放在第一行,this修饰构造器也要放在第一行:
改正二选一即可:
【4】以后写代码构造器的生成可以直接使用IDEA提供的快捷键:alt+insert
继承条件下构造方法的执行过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package com.msb.test10;public class Person { int age; String name; public Person (int age, String name) { super (); this .age = age; this .name = name; } public Person () { } }
1 2 3 4 5 6 7 8 9 10 public class Student extends Person { double height ; public Student () { } public Student (int age, String name, double height) { super (age, name); this .height = height; } }
1 2 3 4 5 6 public class Test { public static void main (String[] args) { Student s = new Student (19 ,"feifei" ,160.8 ); } }
Object类 所有类都直接或间接的继承自Object类,Object类是所有Java类的根基类。 也就意味着所有的Java对象都拥有Object类的属性和方法。 如果在类的声明中未使用extends关键字指明其父类,则默认继承Object类。
toString()方法 【1】Object类的toString()的作用:
方法的原理:
现在,使用toString方法的时候,打印出来的东西 “不好看”,对于其他人来说不友好,可读性不好 我们现在是想知道对象的信息,名字,年龄,身高。。。。。。 现在的格式不好:
出现的问题:子类Student对父类Object提供的toString方法不满意,不满意–》对toString方法进行重写:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package com.msb.test01;public class Student { private String name; private int age; private double height; 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 double getHeight () { return height; } public void setHeight (double height) { this .height = height; } public Student () { } public Student (String name, int age, double height) { this .name = name; this .age = age; this .height = height; } public String toString () { return "这是一个Student对象,这个对象的名字:" +name+",年龄:" +age+",身高:" +height; } }
测试类:
总结:toString的作用就是对对象进行“自我介绍”,一般子类对父类提供的toString都不满意,都要进行重写。
IDEA提供了快捷键:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 package com.msb.test01;public class Student { private String name; private int age; private double height; 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 double getHeight () { return height; } public void setHeight (double height) { this .height = height; } public Student () { } public Student (String name, int age, double height) { this .name = name; this .age = age; this .height = height; } @Override public String toString () { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", height=" + height + '}' ; } }
equals方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 package com.msb.test02;public class Phone { private String brand; private double price; private int year ; public String getBrand () { return brand; } public void setBrand (String brand) { this .brand = brand; } public double getPrice () { return price; } public void setPrice (double price) { this .price = price; } public int getYear () { return year; } public void setYear (int year) { this .year = year; } @Override public String toString () { return "Phone{" + "brand='" + brand + '\'' + ", price=" + price + ", year=" + year + '}' ; } public Phone () { } public Phone (String brand, double price, int year) { this .brand = brand; this .price = price; this .year = year; } public boolean equals (Object obj) { Phone other = (Phone)obj; if (this .getBrand()==other.getBrand()&&this .getPrice()==other.getPrice()&&this .getYear()==other.getYear()){ return true ; } return false ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package com.msb.test02;public class Test { public static void main (String[] args) { Phone p1 = new Phone ("华为P40" ,2035.98 ,2020 ); Phone p2 = new Phone ("华为P40" ,2035.98 ,2020 ); System.out.println(p1==p2); boolean flag = p1.equals(p2); System.out.println(flag); } }
总结: equals作用:这个方法提供了对对象的内容是否相等 的一个比较方式,对象的内容指的就是属性。 父类Object提供的equals就是在比较==地址,没有实际的意义,我们一般不会直接使用父类提供的方法, 而是在子类中对这个方法进行重写。
instanceof
利用集成开发工具生成equals方法 【1】利用eclipse:
【2】利用idea:
类和类的关系 代码
总结: 【1】面向对象的思维:找参与者,找女孩类,找男孩类 【2】体会了什么叫方法的性擦,什么叫方法的实参:
具体传入的内容 实参:
【3】类和类可以产生关系: (1)将一个类作为另一个类中的方法的形参 (2)将一个类作为另一个类的属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class Girl { String name; double weight; Mom m ; public void add (int a) { System.out.println(a); System.out.println(a+100 ); } public void love (Boy b) { System.out.println("我男朋友的名字是:" +b.name+",我男朋友的年龄是:" +b.age); b.buy(); } public void wechat () { m.say(); } public Girl (String name, double weight) { this .name = name; this .weight = weight; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Boy { int age; String name; public void buy () { System.out.println("跟我谈恋爱,我给你买买买。。。" ); } public Boy (int age, String name) { this .age = age; this .name = name; } }
1 2 3 4 5 6 public class Mom { public void say () { System.out.println("妈妈唠唠叨叨 都是爱,听妈妈的话。。" ); } }
总结
一、继承关系 继承指的是一个类(称为子 类、子接口)继承另外的一个类(称为父类、父接口)的功能,并可以增加它自己的新功能的能力。在Java中继承关系通过关键字extends明确标识,在设计时一般没有争议性。在UML类图设计中,继承用一条带空心三角箭头的实线表示,从子类指向父类,或者子接口指向父接口。
二、实现关系 实现指的是一个class类实现interface接口(可以是多个)的功能,实现是类与接口之间最常见的关系。在Java中此类关系通过关键字implements明确标识,在设计时一般没有争议性。在UML类图设计中,实现用一条带空心三角箭头的虚线表示,从类指向实现的接口。
三、依赖关系 简单的理解,依赖就是一个类A使用到了另一个类B,而这种使用关系是具有偶然性的、临时性的、非常弱的,但是类B的变化会影响到类A。比如某人要过河,需要借用一条船,此时人与船之间的关系就是依赖。表现在代码层面,==让类B作为参数被类A在某个method方法中使用。==在UML类图设计中,依赖关系用由类A指向类B的带箭头虚线表示。
四、关联关系 关联体现的是两个类之间语义级别的一种强依赖关系,比如我和我的朋友,这种关系比依赖更强、不存在依赖关系的偶然性、关系也不是临时性的,一般是长期性的,而且双方的关系一般是平等的。关联可以是单向、双向的。表现在代码层面,==为被关联类B以类的属性形式出现在关联类A中==,也可能是关联类A引用了一个类型为被关联类B的全局变量。在UML类图设计中,关联关系用由关联类A指向被关联类B的带箭头实线表示,在关联的两端可以标注关联双方的角色和多重性标记。
五、聚合关系 聚合是关联关系的一种特例,它体现的是整体与部分的关系,即has-a的关系。此时整体与部分之间是可分离的,它们可以具有各自的生命周期,部分可以属于多个整体对象,也可以为多个整体对象共享。比如计算机与CPU、公司与员工的关系等,比如一个航母编队包括海空母舰、驱护舰艇、舰载飞机及核动力攻击潜艇等。==表现在代码层面,和关联关系是一致的,只能从语义级别来区分==。在UML类图设计中,聚合关系以空心菱形加实线箭头表示。
六、组合关系 组合也是关联关系的一种特例,它体现的是一种contains-a的关系,这种关系比聚合更强,也称为强聚合。它同样体现整体与部分间的关系,但此时整体与部分是不可分的,整体的生命周期结束也就意味着部分的生命周期结束,比如人和人的大脑。==表现在代码层面,和关联关系是一致的,只能从语义级别来区分==。在UML类图设计中,组合关系以实心菱形加实线箭头表示。
七、总结 对于继承、实现这两种关系没多少疑问,它们体现的是一种类和类、或者类与接口间的纵向关系。其他的四种关系体现的是类和类、或者类与接口间的引用、横向关系,是比较难区分的,有很多事物间的关系要想准确定位是很难的。前面也提到,==这四种关系都是语义级别的,所以从代码层面并不能完全区分各种关系==,但总的来说,后几种关系所表现的强弱程度依次为:组合>聚合>关联>依赖。
多态(Polymorphism) 【1】多态跟属性无关,多态指的是方法的多态,而不是属性的多态。 【2】案例代入:
1 2 3 4 5 public class Animal { public void shout () { System.out.println("我是小动物,我可以叫。。。" ); } }
1 2 3 4 5 6 7 8 9 public class Cat extends Animal { public void shout () { System.out.println("我是小猫,可以喵喵叫" ); } public void scratch () { System.out.println("我是小猫,我可以挠人" ); } }
1 2 3 4 5 6 7 8 9 public class Dog extends Animal { public void shout () { System.out.println("我是小狗,我可以汪汪叫" ); } public void guard () { System.out.println("我是小狗,我可以看家护院,保护我的小主人。。。" ); } }
1 2 3 4 5 6 7 8 public class Pig extends Animal { public void shout () { System.out.println("我是小猪,我嗯嗯嗯的叫" ); } public void eat () { System.out.println("我是小猪,我爱吃东西。。" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Girl { public void play (Animal an) { an.shout(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class Test { public static void main (String[] args) { Girl g = new Girl (); Pig p = new Pig (); Animal an = p; g.play(an); } }
【3】总结: (1)先有父类,再有子类:–》继承 先有子类,再抽取父类 —-》泛化 (2)什么是多态: 多态就是多种状态:同一个行为,不同的子类表现出来不同的形态。 多态指的就是同一个方法调用,然后由于对象不同会产生不同的行为。
(3)多态的好处: 为了提高代码的扩展性,符合面向对象的设计原则:开闭原则。 开闭原则:指的就是扩展是 开放的,修改是关闭的。 注意:多态可以提高扩展性,但是扩展性没有达到最好,以后我们会学习 反射
(4)多态的要素: 一,继承: Cat extends Animal ,Pig extends Animal, Dog extends Animal 二,重写:子类对父类的方法shout()重写 三, 父类引用指向子类对象:
1 2 Pig p = new Pig ();Animal an = p;
将上面的代码合为一句话: Animal an = new Pig(); =左侧:编译期的类型 =右侧:运行期的类型
Animal an = new Pig(); g.play(an); //
1 2 3 public void play (Animal an) { an.shout(); }
上面的代码,也是多态的一种非常常见的应用场合:父类当方法的形参,然后传入的是具体的子类的对象, 然后调用同一个方法,根据传入的子类的不同展现出来的效果也不同,构成了多态。
内存分析
向下转型,向上转型
现在我就想访问到eat()方法和weight属性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Demo { public static void main (String[] args) { Pig p = new Pig (); Animal an = p; an.shout(); Pig pig = (Pig)an ; pig.eat(); pig.age = 10 ; pig.weight = 60.8 ; } }
对应内存:
思考之前的equals方法:
简单工厂设计模式 不仅可以使用父类做方法的形参,还可以使用父类做方法的返回值类型,真实返回的对象可以是该类的任意一个子类对象。
简单工厂模式的实现,它是解决大量对象创建问题的一个解决方案。将创建和使用分开,工厂负责创建,使用者直接调用即可。简单工厂模式的基本要求是
² 定义一个static方法,通过类名直接调用
² 返回值类型是父类类型,返回的可以是其任意子类类型
² 传入一个字符串类型的参数,工厂根据参数创建对应的子类产品
1 2 3 4 5 6 7 8 9 10 public class Test { public static void main (String[] args) { Girl g = new Girl (); Animal an = PetStore.getAnimal("狗" ); g.play(an); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class PetStore { public static Animal getAnimal (String petName) { Animal an = null ; if ("猫" .equals(petName)){ an = new Cat (); } if ("狗" .equals(petName)){ an = new Dog (); } if ("猪" .equals(petName)){ an = new Pig (); } return an; } }
final 【1】修饰变量;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public class Test { public static void main (String[] args) { final int A = 10 ; final Dog d = new Dog (); d.age = 10 ; d.weight = 13.7 ; final Dog d2 = new Dog (); a(d2); b(d2); } public static void a (Dog d) { d = new Dog (); } public static void b (final Dog d) { } }
【2】修饰方法;
final修饰方法,那么这个方法不可以被该类的子类重写:
【3】修饰类; final修饰类,代表没有子类,该类不可以被继承: 一旦一个类被final修饰,那么里面的方法也没有必要用final修饰了(final可以省略不写)
【4】案例:JDK提供的Math类:看源码发现: (1)使用Math类的时候无需导包,直接使用即可:
(2)Math类没有子类,不能被其他类继承了
(3)里面的属性全部被final修饰,方法也是被final修饰的,只是省略不写了 原因:子类没有必要进行重写。
(4)外界不可以创建对象: Math m = new Math();
(5)发现Math类中的所有的属性,方法都被static修饰 那么不用创建对象去调用,只能通过类名.属性名 类名.方法名 去调用
抽象类,抽象方法 【1】抽象类和抽象方法的关系: 抽象类中可以定义0-n个抽象方法。 【2】抽象类作用: 在抽象类中定义抽象方法,目的是为了为子类提供一个通用的模板,子类可以在模板的基础上进行开发,先重写父类的抽象方法,然后可以扩展子类自己的内容。抽象类设计避免了子类设计的随意性,通过抽象类,子类的设计变得更加严格,进行某些程度上的限制。 使子类更加的通用。
【3】代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 package com.msb.test03;public abstract class Person { public void eat () { System.out.println("一顿不吃饿得慌" ); } public abstract void say () ; public abstract void sleep () ; } class Student extends Person { @Override public void say () { System.out.println("我是东北人,我喜欢说东北话。。" ); } @Override public void sleep () { System.out.println("东北人喜欢睡炕。。" ); } } class Demo { public static void main (String[] args) { Student s = new Student (); s.sleep(); s.say(); Person p = new Student (); p.say(); p.sleep(); } }
【4】面试题: (1)抽象类不能创建对象,那么抽象类中是否有构造器? 抽象类中一定有构造器。构造器的作用 给子类初始化对象的时候要先super调用父类的构造器。
(2)抽象类是否可以被final修饰? 不能被final修饰,因为抽象类设计的初衷就是给子类继承用的。要是被final修饰了这个抽象类了,就不存在继承了,就没有子类。
接口 【1】接口声明格式:
1 2 3 4 [访问修饰符] interface 接口名 [extends 父接口1 ,父接口2 …] { 常量定义; 方法定义; }
【2】代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 package com.msb.test04;public interface TestInterface01 { int NUM = 10 ; void a () ; void b (int num) ; int c (String name) ; } interface TestInterface02 { void e () ; void f () ; } class Student extends Person implements TestInterface01 ,TestInterface02 { @Override public void a () { System.out.println("---1" ); } @Override public void b (int num) { System.out.println("---2" ); } @Override public int c (String name) { return 100 ; } @Override public void e () { System.out.println("---3" ); } @Override public void f () { System.out.println("---4" ); } } class Test { public static void main (String[] args) { TestInterface02 t = new Student (); System.out.println(TestInterface01.NUM); System.out.println(Student.NUM); Student s = new Student (); System.out.println(s.NUM); TestInterface01 t2 = new Student (); System.out.println(t2.NUM); } }
【3】接口的作用是什么?
定义规则,只是跟抽象类不同地方在哪?它是接口不是类。 接口定义好规则之后,实现类负责实现即可。
【4】 继承:子类对父类的继承 实现:实现类对接口的实现
手机 是不是 照相机
继承:手机 extends 照相机 “is-a”的关系,手机是一个照相机
上面的写法 不好:
实现: 手机 implements 拍照功能 “has-a”的关系,手机具备照相的能力
案例:飞机,小鸟,风筝 定义一个接口: Flyable
【5】多态的应用场合: (1)父类当做方法的形参,传入具体的子类的对象 (2)父类当做方法的返回值,返回的是具体的子类的对象 (3)接口当做方法的形参,传入具体的实现类的对象 (4)接口当做方法的返回值,返回的是具体的实现类的对象
【6】接口和抽象类的区别:
JDK1.8以后的接口新增内容 在JDK1.8之前,接口中只有两部分内容: (1)常量:固定修饰符:public static final (2)抽象方法:固定修饰符:public abstract
在JDK1.8之后,新增非抽象方法: (1)被public default修饰的非抽象方法: 注意1:default修饰符必须要加上,否则出错 注意2:实现类中要是想重写接口中的非抽象方法,那么default修饰符必须不能加,否则出错。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public interface TestInterface { public static final int NUM= 10 ; public abstract void a () ; public default void b () { System.out.println("-------TestInterface---b()-----" ); } } class Test implements TestInterface { public void c () { b(); TestInterface.super .b(); } @Override public void a () { System.out.println("重写了a方法" ); } @Override public void b () { } }
(2)静态方法: 注意1:static不可以省略不写 注意2:静态方法不能重写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public interface TestInterface2 { public static final int NUM = 10 ; public abstract void a () ; public default void b () { System.out.println("-----TestInterface2---b" ); } public static void c () { System.out.println("TestInterface2中的静态方法" ); } } class Demo implements TestInterface2 { @Override public void a () { System.out.println("重写了a方法" ); } public static void c () { System.out.println("Demo中的静态方法" ); } } class A { public static void main (String[] args) { Demo d = new Demo (); d.c(); Demo.c(); TestInterface2.c(); } }
疑问:为什么要在接口中加入非抽象方法??? 如果接口中只能定义抽象方法的话,那么我要是修改接口中的内容,那么对实现类的影响太大了,所有实现类都会受到影响。 现在在接口中加入非抽象方法,对实现类没有影响,想调用就去调用即可。
内部类 成员内部类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 package com.msb.test07;public class TestOuter { public class D { int age = 20 ; String name; public void method () { int age = 30 ; System.out.println(age); System.out.println(this .age); System.out.println(TestOuter.this .age); } } static class E { public void method () { } } int age = 10 ; public void a () { System.out.println("这是a方法" ); { System.out.println("这是一个普通块" ); class B { } } class A { } D d = new D (); System.out.println(d.name); d.method(); } static { System.out.println("这是静态块" ); } { System.out.println("这是构造块" ); } public TestOuter () { class C { } } public TestOuter (int age) { this .age = age; } } class Demo { public static void main (String[] args) { TestOuter to = new TestOuter (); to.a(); TestOuter.E e = new TestOuter .E(); TestOuter t = new TestOuter (); TestOuter.D d = t.new D (); } }
局部内部类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 package com.msb.test08;public class TestOuter { public void method () { final int num = 10 ; class A { public void a () { System.out.println(num); } } } public Comparable method2 () { class B implements Comparable { @Override public int compareTo (Object o) { return 100 ; } } return new B (); } public Comparable method3 () { return new Comparable (){ @Override public int compareTo (Object o) { return 200 ; } }; } public void teat () { Comparable com = new Comparable (){ @Override public int compareTo (Object o) { return 200 ; } }; System.out.println(com.compareTo("abc" )); } }
面向对象项目 项目需求
项目结构分析
最终代码 ==匹萨父类:==
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 package com.msb.test01;public class Pizza { private String name; private int size; private int price; public String getName () { return name; } public void setName (String name) { this .name = name; } public int getSize () { return size; } public void setSize (int size) { this .size = size; } public int getPrice () { return price; } public void setPrice (int price) { this .price = price; } public String showPizza () { return "匹萨的名字是:" +name+"\n匹萨的大小是:" +size+"寸\n匹萨的价格:" +price+"元" ; } public Pizza () { } public Pizza (String name, int size, int price) { this .name = name; this .size = size; this .price = price; } }
==培根匹萨:==
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package com.msb.test01;public class BaconPizza extends Pizza { private int weight; public int getWeight () { return weight; } public void setWeight (int weight) { this .weight = weight; } public BaconPizza () { } public BaconPizza (String name, int size, int price, int weight) { super (name, size, price); this .weight = weight; } @Override public String showPizza () { return super .showPizza()+"\n培根的克数是:" +weight+"克" ; } }
==水果匹萨:==
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package com.msb.test01;public class FruitsPizza extends Pizza { private String burdening; public String getBurdening () { return burdening; } public void setBurdening (String burdening) { this .burdening = burdening; } public FruitsPizza () { } public FruitsPizza (String name, int size, int price, String burdening) { super (name, size, price); this .burdening = burdening; } @Override public String showPizza () { return super .showPizza()+"\n你要加入的水果:" +burdening; } }
==测试类:==
1 2 3 4 5 6 7 8 9 10 11 12 public class Test { public static void main (String[] args) { Scanner sc = new Scanner (System.in); System.out.println("请选择你想要购买的匹萨(1.培根匹萨 2.水果匹萨):" ); int choice = sc.nextInt(); Pizza pizza = PizzaStore.getPizza(choice); System.out.println(pizza.showPizza()); } }
==工厂类:==
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 package com.msb.test01;import java.util.Scanner;public class PizzaStore { public static Pizza getPizza (int choice) { Scanner sc = new Scanner (System.in); Pizza p = null ; switch (choice){ case 1 : { System.out.println("请录入培根的克数:" ); int weight = sc.nextInt(); System.out.println("请录入匹萨的大小:" ); int size = sc.nextInt(); System.out.println("请录入匹萨的价格:" ); int price = sc.nextInt(); BaconPizza bp = new BaconPizza ("培根匹萨" ,size,price,weight); p = bp; } break ; case 2 : { System.out.println("请录入你想要加入的水果:" ); String burdening = sc.next(); System.out.println("请录入匹萨的大小:" ); int size = sc.nextInt(); System.out.println("请录入匹萨的价格:" ); int price = sc.nextInt(); FruitsPizza fp = new FruitsPizza ("水果匹萨" ,size,price,burdening); p = fp; } break ; } return p; } }