第5章 程序控制结构
5.1 五种控制结构
if-else
if(age>18){System.out.println(" ");} else {System.out.println(" ");}
switch
switch(c1) {case 'a' :System.out.println("A");break;case 'b' :System.out.println("B");break;case 'c' :case 'd' :case 'e' :System.out.println("C,D,E");break;default :System.out.println("你的输入有误~")
for
for(int i= 0 , j = 0; i<100; i++,j++;){System.out.println("i=" + i +"j="+ j);}
while
while 循环也有四要素只是四要素放的位置和for比一样
while(i<=10){System.out.println(" ");i++;}
do…while
循环变量初始化;
do{
循环体(语句);
循环变量迭代;
}while(循环条件);
do{System.out.println( );i++;}while(i<=10);
5.2 switch 注意事项
例题
对学生成绩大于 60 分的,输出"合格"。低于 60 分的,输出"不合格"。(注:输入的成绩不能大于 100), 提示 成绩/60*
提示
这里我们需要进行一个转换, 编程思路 :
如果成绩在 [60,100] , (int)(成绩/60) = 1
如果成绩在 [0,60) , (int)(成绩/60) = 0
if( score >= 0 && score <= 100) {switch ((int)(score / 60)) {case 0 :System.out.println("不合格");break;case 1 :System.out.println("合格");break;// default :// System.out.println("输入有误");}} else {System.out.println("输入的成绩在 0-100");}
switch 和 if 的比较
如果判断的具体数值不多,而且符合 byte、 short 、int、 char, enum[枚举], String 这 6 种类型。虽然两个语句都可 以使用,建议使用 swtich 语句。其他情况:对区间判断,对结果为 boolean 类型判断,使用 if,if 的使用范围更广
5.3 for 注意事项
循环条件是返回一个布尔值的表达式for(;循环判断条件;) 中的初始化和变量迭代可以写到其它地方,但是两边的分号不能省略。循环初始值可以有多条初始化语句,但要求类型一样,并且中间用逗号隔开,循环变量迭代也可以有多条变量迭代 语句,中间用逗号隔开。###5.83 while 注意事项
循环条件是返回一个布尔值的表达式while 循环是先判断再执行语句
5.4 do…while
先执行,再判断,也就是说,一定会至少执行一次最后 有一个 分号 ;while 和 do…while 区别举例: 要账5.5 多重循环控制
设外层循环次数为 m 次,内层为 n 次,则内层循环体实际上需要执行 m*n 次。
九九乘法表
public class Test {/*** java实现九九乘法*/public static void main(String[] args) {//九九乘法for(int i = 1;i <= 9;i++){for(int j = 1;j <= i;j++){System.out.print(j+"*"+ i +"="+i*j+" ");//此处用的print}System.out.println();}}
5.6经典的打印的金字塔
矩形*************************for(int i = 1;i <=5;i++){System.out.println("*****");}
打印半个金字塔
* //第 1 层 有 1 个*** //第 2 层 有 2 个**** //第 3 层 有 3 个***** //第 4 层 有 4 个****** //第 5 层 有5个*public class Switch{//编写一个main方法public static void main(String[] args) {for(int i = 1;i <= 5;i++){//i表示层数//控制打印每层的*的个数for(int j = 1;j<=i;j++){System.out.print("*");}//每打印完一层的*后,就换行System.out.println("");//println本身会换行,//或者用System.out.print("\n");}}}
打印整个金字塔
* //第 1 层 有 1 个* 2 * 1 -1 有 4=(总层数-1)个空格*** //第 2 层 有 3 个* 2 * 2 -1 有 3=(总层数-2)个空格***** //第 3 层 有 5 个* 2 * 3 -1 有 2=(总层数-3)个空格******* //第 4 层 有 7 个* 2 * 4 -1 有 1=(总层数-4)个空格********* //第 5 层 有 9 个* 2 * 5 -1 有 0=(总层数-5)个空格public class Switch{//编写一个main方法public static void main(String[] args) {for(int i = 1;i <= 5;i++){//i表示层数//在输出*之前,还要输出 对应空格 = 总层数-当层数for(int k = 1;k <= 5-i;k++){System.out.print(" ");}//控制打印每层的*的个数for(int j = 1;j<=2*i-1;j++){System.out.print("*");}//每打印完一层的*后,就换行System.out.println("");//println本身会换行,//或者用System.out.print("\n");}}}
打印空心的金字塔 [最难的]
* //第 1 层 有 1 个* 当前行的第一个位置是*,最后一个位置也是** * 第 2 层 有 2 个* 当前行的第一个位置是*,最后一个位置也是** * 第 3 层 有 2 个* 当前行的第一个位置是*,最后一个位置也是*** 第 4 层 有 2 个* 当前行的第一个位置是*,最后一个位置也是********** //第 5 层 有 9 个* 全部输出*import java.util.Scanner;public class Switch{public static void main(String[] args){Scanner myScanner = new Scanner(System.in);System.out.println("输出几行星星:");int line = myScanner.nextInt();for(int i=1; i<=line;i++){for(int k=1;k<=line-i;k++){System.out.print(" ");//前边的空格数}for(int j=1;j<=2*i-1;j++){if(j==1||j==2*i-1||i==line){//每行第一个和最后一个和最后一行输出*System.out.print("*");}else{System.out.print(" ");}}System.out.println(" ");//换行}}}
自己写的空心菱形
import java.util.Scanner;public class Switch{public static void main(String[] args){Scanner myScanner = new Scanner(System.in);System.out.println("输出上半部分为几行星星:");int line = myScanner.nextInt();//上半部分for(int i=1; i<=line;i++){for(int k=1;k<=line-i;k++){System.out.print(" ");//前边的空格数}for(int j=1;j<=2*i-1;j++){if(j==1||j==2*i-1){//每行第一个和最后一个和最后一行输出*System.out.print("*");}else{System.out.print(" ");}}System.out.println(" ");//换行}//下半部分for(int a =line-1; a>=1;a--){for(int c = line-a;c>=1;c--){System.out.print(" ");}for (int b=1;b<=2*a-1;b++){if(b==1||b==2*a-1){//每行第一个和最后一个和最后一行输出*System.out.print("*");}else{System.out.print(" ");}}System.out.println(" ");//换行}}}
5.7 跳转控制语句break注意事项
(1)break 语句可以指定退出那层
(2)label1 是标签,名字由程序员指定。
(3)break 后指定到那个label 就退出到哪里。
(4)在实际的开发中,尽量不要使用标签。
(5)如果没有指定 break ,默认退出最近的循环体
随机数 random
Math.random()//public static double random()返回带正号的 double 值,该值大于等于 0.0 且小于 1.0。返回值是一个伪随机选择的数,在该范围内(近似)均匀分布。 //0.47499987617404070.412386966275462560.084959148528738430.0342776451405425450.36542069380683640.451686957568369740.67270952269476640.45505129024644540.8100140526769770.044614912679679320.12219404584351146 (int)(Match.random()*100)+1//加一是因为,前边乘以100范围是0~99,加1之后范围就到了0~100了。
字符串比较 equals
if("丁真".equals(name) && "666".equals(passwd)) {System.out.println("恭喜你,登录成功~");break;}
判断“丁真”和name这两个字符串是否相等。
5.8 跳转控制语句continue
continue 语句用于结束本次循环,继续执行下一次循环。continue 语句出现在多层嵌套的循环语句体中时,可以通过标签指明要跳过的是哪一层循环 , 这个和前面的标签的 使用的规则一样.###5.13 跳转控制语句retuen
return 使用在方法,表示跳出所在的方法,如果 return 写在 main 方法,退出程序。
5.9本章作业
求出1-1/2+1/3-1/4…1/100的和
注意1.0/j中的数字1.0不能写成1
//自己写的public class Switch{public static void main(String[] args){double sum=0;int a=1;for(int j=1;j<=100;j++){if(j%2==0){a=-1;}else{a=1;}sum=sum+(1.0/j)*a;//这的1.0不能写成1//写成1的话这个除法1/j得到的就是0了!}System.out.println("sum="+sum);}}//老师的public class Homework08 {//编写一个main方法public static void main(String[] args) {/*求出1-1/2+1/3-1/4…..1/100的和思路分析1. 1-1/2+1/3-1/4…..1/100 = (1/1)-(1/2)+(1/3)-(1/4)...1/1002. 从上面的分析我们可以看到 (1) 一共有100数 , 分子为1 , 分母从1-100(2) 还发现 当分母为奇数时,前面是 +, 当分母是偶数时,前面是-3. 我们可以使用 for + 判断即可完成4. 把结果存放到 double sum 5. 这里有一个隐藏的陷阱,要把 公式分子 1 写出1.0 才能得到精确的小数*/double sum = 0;for(int i = 1; i <= 100; i++) {//判断是奇数还是偶数,然后做不同的处理if( i % 2 != 0) {//分母为奇数sum += 1.0/i;} else {//分母我偶数sum -= 1.0/i;}}System.out.println("sum=" + sum);}}
求1+(1+2)+(1+2+3)+(1+2+3+4)+…+(1+2+3+…+100)的结果
public class Switch{public static void main(String[] args){int sum=0;for(int i=1;i<=100;i++){for(int j=1;j<=i;j++){sum+=j;}}System.out.println("sum="+ sum);}}
第 6 章 数组、排序和查找
6.1 冒泡序列
这样一层循环只是把最大的一个数排到了最后public class BubbleSort{public static void main(String[] args){int[] arr={24,68,-2,1,6};int max=0;for(int i=0;i<arr.length-1;i++){if(arr[i]>arr[i+1]){max=arr[i];arr[i]=arr[i+1];arr[i+1]=max;}System.out.println("第"+(i+1)+"轮");for(int j=0;j<arr.length;j++){System.out.print(arr[j]+"\t");}System.out.println();}}}
双重循环最后一下把所有的数从小排到大
public class BubbleSort{public static void main(String[] args){int[] arr={24,68,-2,1,6};int max=0;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]){max=arr[j];arr[j]=arr[j+1];arr[j+1]=max;}System.out.println("第"+(i+1)+"轮");for(int j=0;j<arr.length;j++){System.out.print(arr[j]+"\t");}System.out.println();}}}
6.2 数组的使用
使用方式1-动态初始化
数组的定义: 数组类型 数组名[] = new 数据类型[大小]
int a[] = new int[5];
使用方式2-动态初始化
数据类型 数组名[]; 也可以 数据类型[] 数组名;
int a[]; 或者 int[] a;//声明数组,这时 a 是 null
数组名 = new 数据类型[大小];
a = new int[10]//分配内存空间,可以存放数据
使用方式3-静态初始化
数据类型 数组名[] = {元素值,元素值…}
int a[]={2,5,6,90,65,33}
注意:
数组创建后,如果没有赋值,有默认值
int 0,short 0, byte 0, long 0, float 0.0,double 0.0,char \u0000,boolean false,String null
数组属引用类型,数组型数据是对象(object)
6.3 数组赋值机制
基本数据类型赋值,这个值就是具体的数据,而且相互不影响。
int n1 = 2; int n2 = n1;
int a=10;int b=a;b=80;System.out.println(a);// 10System.out.println(b);// 80
数组在默认情况下是引用传递,赋的值是地址。
public class ArrayDetail{public static void main(String[] args){int[] a={1,2,3};int[] b=a;b[1]=9;for (int i=0;i<a.length;i++){System.out.print(a[i]+" ");//1 9 3}System.out.println();for(int i=0;i<b.length;i++){System.out.print(b[i]+ " ");//1 9 3}}}
这样数组a和数组b就互不干扰了
重新定义一个数组b
public class ArrayDetail{public static void main(String[] args){int[] a={1,2,3};int[] b=new int[a.length];for(int i = 0; i < a.length; i++) {b[i] = a[i];}b[1]=9;for (int i=0;i<a.length;i++){System.out.print(a[i]+" ");//1 2 3}System.out.println();for(int i=0;i<b.length;i++){System.out.print(b[i]+ " ");//1 9 3}}}
6.4 数组的增加
用户可以通过如下方法来决定是否继续添加,添加成功,是否继续?y/n官方答案
import java.util.Scanner;public class ArrayDetail{public static void main(String[] args){Scanner myScanner=new Scanner(System.in);int[] arr={1,2,3};do{int[] arr2=new int[arr.length +1];for(int i=0;i<arr.length;i++){arr2[i]=arr[i];}System.out.println("请输入你要增加的元素:");int num=myScanner.nextInt();arr2[arr2.length - 1]=num;arr=arr2;// 让 arr 指向 arr2; arr = arr2; 那么 原来 arr 数组就被销毁System.out.println("===arr扩容后元素的情况====");for(int i=0;i<arr.length;i++){System.out.print(arr[i]+" ");}//问用户是否继续System.out.println();System.out.println("是否继续添加 y/n");char key = myScanner.next().charAt(0);if(key=='n'){//如果输入n,就结束break;}}while(true);System.out.println("你退出了增加...");}}
自己写的,在数组int[] arr={1,2,3}的基础上定义增加几个数值,然后录入,输入。(结束后内存里是两个数组,改进是一个)
import java.util.Scanner;public class ArrayDetail{public static void main(String[] args){Scanner myScanner=new Scanner(System.in);int[] arr={1,2,3};System.out.println("请输入要加入的个数:");int n = myScanner.nextInt();int[] arr2=new int[arr.length+n];for(int i=0;i<arr.length;i++){arr2[i]=arr[i];}System.out.println("请输入:");for(int i=0;i<n;i++){int m=myScanner.nextInt();arr2[arr.length+i]=m;}//1. arr=arr2; 用这个销毁原来的数组arrfor(int i=0;i<arr2.length;i++){//2. 再把这的arr2换成arr就行了System.out.print(arr2[i]+" "); //这种方法比自己的好,能减少一个数组。}}}
6.5 二维数组
使用方式 1: 动态初始化
语法: 类型[][] 数组名=new 类型【大小】【大小】
比如: int a[][]=new int[2] [3];
使用方式 2: 动态初始化
先声明:类型 数组名[][];
再定义(开辟空间) 数组名 = new 类型[大小] [大小]
赋值(有默认值,比如 int 类型的就是 0)
使用方式 3: 动态初始化-列数不确定
int[][] arr = new int[3] [];
使用方式 4: 静态初始化
定义 类型 数组名[][] = {{值 1,值 2…},{值 1,值 2…},{值 1,值 2…}}
int[] [] arr = {{1,1,1}, {8,8,9}, {100}};
6.6 杨辉三角形
规律1.第一行有 1 个元素, 第 n 行有 n 个元素2. 每一行的第一个元素和最后一个元素都是 13. 从第三行开始, 对于非第一个元素和最后一个元素的元素的值. arr[i][j]arr[i][j] = arr[i-1][j] + arr[i-1][j-1]; //必须找到这个规律public class ArrayDetail{public static void main(String[] args){int[][] yangHui = new int[12][];for(int i=0;i<yangHui.length;i++){yangHui[i]=new int[i+1];//给每个一维数组(行)开空间for(int j= 0;j<yangHui[i].length;j++){if(j==0 || j==yangHui[i].length-1){yangHui[i][j]=1;}else{yangHui[i][j] = yangHui[i-1][j]+yangHui[i-1][j-1];}}}//输出杨辉三角形for(int i=0;i<yangHui.length;i++){for(int j =0;j<yangHui[i].length;j++){System.out.print(yangHui[i][j]+"\t");}System.out.println();}}}
6.7 二维数组使用细节和注意事项
一维数组的声明方式有:
int[] x 或者 int x[]
二维数组的声明方式有:
int[] [] y 或者 int[] y[] 或者 int y[] []
二维数组实际上是由多个一维数组组成的,它的各个一维数组的长度可以相同,也可以不相同。
6.8 本章作业
下面数组定义正确的有B,D
String foo = "blue";boolean[] bar = new booolean[2];//数组bar[]默认的都是falseif(bar[0]){//bar[0]为false,所以不进入foo="green";}System.out.println(foo);// 仍然为blue
3.
public class Homework04 {//编写一个main方法public static void main(String[] args) {/*已知有个升序的数组,要求插入一个元素,该数组顺序依然是升序, 比如: [10, 12, 45, 90], 添加23 后, 数组为 [10, 12,23, 45, 90]思路 本质数组扩容 + 定位1. 我们先确定 添加数应该插入到哪个索引2. 然后扩容*///先定义原数组int[] arr = {10, 12, 45, 90};int insertNum = 111;int index = -1; //index就是要插入的位置//遍历 arr数组, 如果发现 insertNum<=arr[i], 说明 i 就是要插入的位置//使用 index 保留 index = i;//如果遍历完后,没有发现 insertNum<=arr[i], 说明 index = arr.length//即:添加到arr的最后for(int i = 0; i < arr.length; i++) {if(insertNum <= arr[i]) {index = i;break; //找到位置后,就退出}}//判断index 的值if(index == -1) {//说明没有还没有找到位置index = arr.length;}//扩容//先创建一个新的数组,大小 arr.length + 1int[] arrNew = new int[arr.length + 1];//下面老师准备将arr的元素拷贝到 arrNew ,并且要跳过 index位置/*分析:int[] arr = {10, 12, 45, 90};arrNew = { }*///i 控制arrNew的下标 , j用来控制arr数组的下标for(int i = 0, j = 0; i < arrNew.length; i++) {if( i != index ) {//说明可以把 arr的元素拷贝到 arrNewarrNew[i] = arr[j];j++;} else {//i这个位置就是要插入的数arrNew[i] = insertNum;}}//让arr 指向 arrNew , 原来的数组,就成为垃圾,被销毁arr = arrNew;System.out.println("======插入后,arr数组的元素情况======");for(int i = 0; i < arr.length; i++) {System.out.print(arr[i] + "\t");}}}
随机生成10个整数(1-100)保存到数组; 在数组中找是否有8
for(int i = 0; i < arr.length; i++) {arr[i] = (int)(Math.random() * 100) + 1;}int findNum = 8;int index = -1; //如果找到,就把下标记录到 indexfor(int i = 0; i < arr.length; i++) {if(findNum == arr[i]) {System.out.println("找到数" + findNum + " 下标=" + i);index = i;break;}}if(index == -1) {System.out.println("没有找到数" + findNum );}
第 7 章 面向对象编程(基础部分)
7.1 类与对象
类和对象的区别 类是抽象的,概念的,代表一类事物,比如人类,猫类…, 即它是数据类型.对象是具体的,实际的,代表一个具体事物, 即 是实例.类是对象的模板,对象是类的一个个体,对应一个实例7.2对象在内存中存在形式(重要的)必须搞清楚。
7.3 如何创建对象
先声明再创建
Cat cat ; //声明对象 cat
cat = new Cat(); //创建
直接创建 Cat cat = new Cat();
public class Object{public static void main(String[] args){Cat cat1 = new Cat();cat1.name="小白";cat1.age=3;cat1.color="白色";System.out.println("第一只猫的信息"+cat1.name+" "+cat1.age+" "+cat1.color);}}class Cat{int age;String name;String color;}
7.4 类和对象的内存分配机制
Java 内存的结构分析
栈: 一般存放基本数据类型(局部变量)堆: 存放对象(Cat cat , 数组等)方法区:常量池(常量,比如字符串), 类加载信息
Java 创建对象的流程简单分析
先加载 Person 类信息(属性和方法信息, 只会加载一次)在堆中分配空间, 进行默认初始化(看规则)把地址赋给 p , p 就指向对象进行指定初始化, 比如 p.name =”jack” p.age = 10
Person a=new Person();a.age=10;a.name="小明";Person b;b=a;System.out.println(b.name); //小明b.age=200;b=null; //把b的地址null,b现在谁也不指向了System.out.println(a.age); //200System.out.println(b.age); //异常
7.5 基本数据类型的传参机制
public class MethodParameter01 {//编写一个 main 方法public static void main(String[] args) {int a = 10;int b = 20;//创建 AA 对象 名字 objAA obj = new AA();obj.swap(a, b); //调用 swapSystem.out.println("main 方法 a=" + a + " b=" + b);//a=10 b=20}}class AA {public void swap(int a,int b){System.out.println("\na 和 b 交换前的值\na=" + a + "\tb=" + b);//a=10 b=20//完成了 a 和 b 的交换int tmp = a;a = b;b = tmp;System.out.println("\na 和 b 交换后的值\na=" + a + "\tb=" + b);//a=20 b=10}}
7.6 引用数据类型的传参机制
看一个案例 MethodParameter02.java
B 类中编写一个方法 test100,可以接收一个数组,在方法中修改该数组,看看原来的数组是否变化?会变化
B 类中编写一个方法 test200,可以接收一个 Person(age,sal)对象,在方法中修改该对象属性,看看原来的对象是否变化?会变化.(注意看一个类中怎样调用另一个类。跨类中的方法A类调用B类方法:需要通过对象调用。比如 对象名.方法名(参数) )
public class Object{public static void main(String[] args){B b=new B();int arr[]={1,2,3};b.test100(arr);System.out.println("主方法中的");for(int i=0;i<arr.length;i++){System.out.print(arr[i]+"\t");}Ren mo = new Ren();mo.name="jack";mo.age=20;b.test200(mo); //注意看这一点System.out.println(mo.age);}}class Ren{String name;int age;}class B{public void test200(Ren mo){//注意看mo.age=10000;}public void test100(int arr[]){arr[0]=123;System.out.println("类中的");for(int i=0;i<arr.length;i++){System.out.print(arr[i]+"\t");}}}
7.7成员方法返回类型是引用类型应用实例
编写一个方法 copyPerson,可以复制一个 Person 对象,返回复制的对象。克隆对象, 注意要求得到新对象和原来的 对象是两个独立的对象,只是他们的属性相同。
public class MethodExercise02 {//编写一个main方法public static void main(String[] args) {Person p = new Person();p.name = "milan";p.age = 100;//创建toolsMyTools tools = new MyTools();Person p2 = tools.copyPerson(p);//到此 p 和 p2是Person对象,但是是两个独立的对象,属性相同System.out.println("p的属性 age=" + p.age + " 名字=" + p.name);System.out.println("p2的属性 age=" + p2.age + " 名字=" + p2.name);//这里老师提示: 可以同 对象比较看看是否为同一个对象System.out.println(p == p2);//false}}class Person {String name;int age;}class MyTools {//编写一个方法copyPerson,可以复制一个Person对象,返回复制的对象。克隆对象, //注意要求得到新对象和原来的对象是两个独立的对象,只是他们的属性相同////编写方法的思路//1. 方法的返回类型 Person//2. 方法的名字 copyPerson//3. 方法的形参 (Person p)//4. 方法体, 创建一个新对象,并复制属性,返回即可public Person copyPerson(Person p) {//创建一个新的对象Person p2 = new Person();p2.name = p.name; //把原来对象的名字赋给p2.namep2.age = p.age; //把原来对象的年龄赋给p2.agereturn p2;}}
7.8 递归举例
距离问题
阶乘问题
public class Recursion01 {//编写一个 main 方法public static void main(String[] args) {T t1 = new T();t1.test(4);//输出什么? n=2 n=3 n=4int res = t1.factorial(5);System.out.println("5 的阶乘 res =" + res);}}class T {//分析public void test(int n) {if (n > 2) {test(n - 1);}System.out.println("n=" + n);}}//factorial 阶乘public int factorial(int n) {if (n == 1) {return 1;} else {return factorial(n - 1) * n;}}}
(老鼠迷宫,汉诺塔,八皇后例子没有写,有空注意一下,很有意思)
7.9 方法重载
java 中允许同一个类中,多个同名方法的存在,但要求 形参列表不一致!方法名必须相同,形参列表必须相同(形参类型或个数或顺序,至少有一样不同,参数名无要求),返回类型无要求。7.10 可变参数
java 允许将同一个类中多个同名同功能但参数个数不同的方法,封装成一个方法。 就可以通过可变参数实现。
基本语法:访问修饰符 返回类型 方法名(数据类型… 形参名) {
}
public int sum(int... nums) {//可以任意多个数相加int res = 0;for(int i = 0; i < nums.length; i++) {res += nums[i];}return res;}}
可变参数的实参可以为0个活任意多个。
可变参数色实参可以为数组。
可变参数的本质就是数组
可变参数可以和普通类型的参数一起放在有形参列表,但必须保证可变参数在最后
一个形参列表中只能出现一个可变参数
里边有一个publicStringshowScore(String name ,double… scores)
注意string.
public class VarParameterExercise {//编写一个 main 方法public static void main(String[] args) {HspMethod hm = new HspMethod();System.out.println(hm.showScore("milan" , 90.1, 80.0 ));System.out.println(hm.showScore("terry" , 90.1, 80.0,10,30.5,70 ));}}class HspMethod {/*有三个方法,分别实现返回姓名和两门课成绩(总分),返回姓名和三门课成绩(总分),返回姓名和五门课成绩(总分)。封装成一个可变参数的方法*///分析 1. 方法名 showScore 2. 形参(String ,double... ) 3. 返回 Stringpublic String showScore(String name ,double... scores){double totalScore = 0;for(int i = 0; i < scores.length; i++) {totalScore += scores[i];}return name + " 有 " +scores.length + "门课的成绩总分为=" + totalScore;}}
7.11 作用域
public class VarScopeDetail{//编写一个 main 方法public static void main(String[] args) {Person p1 = new Person();/*属性生命周期较长,伴随着对象的创建而创建,伴随着对象的销毁而销毁。局部变量,生命周期较短,伴随着它的代码块的执行而创建,伴随着代码块的结束而销毁。即在一次方法调用过程中*///p1.say();//当执行 say 方法时,say 方法的局部变量比如 name,会创建,当 say 执行完毕后//name 局部变量就销毁,但是属性(全局变量)仍然可以使用//T t1 = new T();t1.test(); //第 1 种跨类访问对象属性的方式t1.test2(p1);//第 2 种跨类访问对象属性的方式}}class T {//全局变量/属性:可以被本类使用,或其他类使用(通过对象调用)public void test() {Person p1 = new Person();System.out.println(p1.name);//jack}public void test2(Person p) {System.out.println(p.name);//jack}}class Person {//细节: 属性可以加修饰符(public protected private..)// 局部变量不能加修饰符public int age = 20;String name = "jack";public void say() {//细节 属性和局部变量可以重名,访问时遵循就近原则String name = "king";System.out.println("say() name=" + name);}public void hi() {String address = "北京";//String address = "上海";//错误,重复定义变量String name = "hsp";//可以}}
7.12 构造器
基本语法
[修饰符] 方法名(形参列表){
方法体;
}
构造器的修饰符可以默认, 也可以是 public protected private构造器没有返回值方法名 和类名字必须一样参数列表 和 成员方法一样的规则构造器的调用, 由系统完成 基本介绍 构造方法又叫构造器(constructor),是类的一种特殊的方法,它的主要作用是完成对新对象的初始化。它有几个特点: 方法名和类名相同没有返回值在创建对象时,系统会自动的调用该类的构造器完成对象的初始化 注意事项
7.13 this关键字
案例this 的注意事项和使用细节
this 关键字可以用来访问本类的属性、方法、构造器this 用于区分当前类的属性和局部变量访问成员方法的语法:this.方法名(参数列表);访问构造器语法:this(参数列表); 注意只能在构造器中使用(即只能在构造器中访问另外一个构造器, 必须放在第一 条语句)this 不能在类定义的外部使用,只能在类定义的方法中使用。
this案例
定义 Person 类,里面有 name、age 属性,并提供 compareTo 比较方法,用于判断是否和另一个人相等,提供测试类 TestPerson 用于测试, 名字和年龄完全一样,就返回 true, 否则返回 false
public class TestPerson {//编写一个 main 方法public static void main(String[] args) {Person p1 = new Person("mary", 20);Person p2 = new Person("mary", 20);System.out.println("p1 和 p2 比较的结果=" + pareTo(p2));}}/*定义 Person 类,里面有 name、age 属性,并提供 compareTo 比较方法,用于判断是否和另一个人相等,提供测试类 TestPerson 用于测试, 名字和年龄完全一样,就返回 true, 否则返回 false*/class Person {String name;int age;//构造器public Person(String name, int age) {this.name = name;this.age = age;}//compareTo 比较方法public boolean compareTo(Person p) {//名字和年龄完全一样// if(this.name.equals(p.name) && this.age == p.age) {// return true;// } else {// return false;// }return this.name.equals(p.name) && this.age == p.age;}}
7.14 课后作业
编程创建一个Cale计算类,在其中定义2个变量表示2个操作数,定义4个方法实现求和、差、乘、商(要求除数为0的话,要提示)并创建2个对象,分别测试。(注意除数中Double的大小写,有点搞不懂)
public class Homework06 {//编写一个main方法public static void main(String[] args) {Cale cale = new Cale(2, 10);System.out.println("和=" + cale.sum());System.out.println("差=" + cale.minus());System.out.println("乘=" + cale.mul());Double divRes = cale.div();if(divRes != null) {System.out.println("除=" + divRes);} }}/*编程创建一个Cale计算类,在其中定义2个变量表示两个操作数,定义四个方法实现求和、差、乘、商(要求除数为0的话,要提示) 并创建两个对象,分别测试 */class Cale {double num1;double num2;public Cale(double num1, double num2) {this.num1 = num1;this.num2 = num2;}//和public double sum() {return num1 + num2;}//差public double minus() {return num1 - num2;}//乘积public double mul() {return num1 * num2;}//除法//public Double div() {//判断if(num2 == 0) {System.out.println("num2 不能为0");return null;} else {return num1 / num2;}}}
7.
public class Test {//公有类int count = 9; //属性public void count1() {//Test类的成员方法count=10;//这个count就是属性 改成 10System.out.println("count1=" + count); //10 }public void count2() {//Test类的成员方法System.out.println("count1=" + count++);} //这是Test类的main方法, 任何一个类,都可有mainpublic static void main(String args[]) {//老韩解读//1. new Test()是匿名对象, 匿名对象使用后,就不能使用//2. new Test().count1() 创建好匿名对象后, 就调用count1()new Test().count1(); Test t1= new Test();t1.count2();//9t1.count2();//10}}
10.
第8章 面向对象编程(中级部分)
8.1 IDEA 常用快捷键
删除当前行, 默认是 ctrl + Y
复制当前行,默认是crtl + D
补全代码 alt + /
添加注释和取消注释 ctrl + / 【第一次是添加注释,第二次是取消注释】
导入该行需要的类 先配置 auto import , 然后使用 alt+enter 即可
快速格式化代码 ctrl + alt + L
快速运行程序 自己定义 alt + R
生成构造器等 alt + insert [提高开发效率]
查看一个类的层级关系 ctrl + H [学习继承后,非常有用]
将光标放在一个方法上,输入 ctrl + B , 可以定位到方法 [学继承后,非常有用]
自动的分配变量名 , 通过 在后面假 .var [老师最喜欢的]
8.2 包
8.2.1 包的三大作用
区分相同名字的类当类很多时,可以很好的管理类【看Java API文档】控制访问范围8.2.2 包的基本语法
.student;
package 关键字,表示打包。com.student 表示包名。
8.2.3 包的基本分析
8.2.4 包的命名
命名规则:
只能包含数字、字母、下划线、小圆点,但不能用数字开头,不能是关键字或者保留字。
命名规范:
一般是小写字母+小圆点
一般是com.公司名.项目名.业务板块名
8.2.5 常用的包
一个包下,包含很多的类,java中常用的包有:
java.lang.* //lang包是基本包,默认引入,不需要再引入。java.util.* //util 包,系统提供的工具包,工具类,使用 .* //网络包,网络开发java.awt* //是做java的界面开发,GUI
8.2.6 如何引入包
在java中,为了装载已编译好的包,通常可使用以下三种方法。
在要引用的类名前带上包名作为修饰符。
Animals.Cat cat = new Animals Cat();
其中,Animals是包名,Cat是包中的类,cat是类的对象。
在文件开头使用 import 引用包中的类。
import Animals.Cat;
class Check{
Cat cat = new Cat( );
}
同样,Animals是包名,Cat是包中的类,cat是创建的Cat类对象。
在文件前使用 import 引入整个包。
import Animals. *;
Animals整个包被引入。(在引入包时,可以用点“ . ”表示出包所在的层次结构,如经常使用的:
import java.io.*;
import java.applet.* ;
实际是引入了/java/io/或/java/applet/这样的目录结构下的所有内容。)
8.2.7 注意事项和使用细节
package 的作用是声明当前类所在的包,需要放在类的最上面,一个类中最多只有一句package。import 指令位置放在package的下面,在类定义前面,可以有多句且没有顺序要求。8.3 访问修饰符
8.3.1基本介绍
java 提供四种访问控制修饰符号,用于控制方法和属性(成员变量)的访问权限(范围):
公开级别:用 public 修饰,对外公开受保护级别:用 protected 修饰,对子类和同一个包中的类公开默认级别:没有修饰符号,向同一个包的类公开私有级别:用 private 修饰,只有类本身可以访问,不对外公开
8.3.2 4种访问修饰符的访问范围
8.3.3使用的注意事项
修饰符可以用来修饰类中的属性,成员方法以及类只有默认的和public才能修饰类!并且遵循上述访问权限的特点。成员方法的访问规则和属性一样8.4 面向对象编程三大特征
8.4.1基本介绍
面向对象编程有三大特征:封装、继承和多态。
8.4.2封装介绍
8.4.3封装的理解和好处
8.4.4 封装的实现步骤 (三步)
8.5 面向对象编程-继承
8.5.1 继承基本介绍和示意图
继承可以解决代码复用,让我们的编程更加靠近人类思维.当多个类存在相同的属性(变量)和方法时,可以从这些类中 抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过 extends 来 声明继承父类即可。画出继承的示意图
8.5.2 继承的基本语法
8.5.3 继承给编程带来的便利
代码的复用性提高了代码的扩展性和维护性提高了8.5.4继承的深入讨论/细节问题
子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问, 但是私有属性和方法不能在子类直接访 问,要通过父类提供公共的方法去访问子类必须调用父类的构造器, 完成父类的初始化当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无 参构造器,则必须在子类的构造器中用 super 去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过如果希望指定去调用父类的某个构造器,则显式的调用一下 : super(参数列表)super 在使用时,必须放在构造器第一行(super 只能在构造器中使用)super() 和 this() 都只能放在构造器第一行,因此这两个方法不能共存在一个构造器java 所有类都是 Object 类的子类, Object 是所有类的基类父类构造器的调用不限于直接父类!将一直往上追溯直到 Object 类(顶级父类)子类最多只能继承一个父类(指直接继承),即 java 中是单继承机制。不能滥用继承,子类和父类之间必须满足 is-a 的逻辑关8.5.5 继承的本质分析(重要)
我们看一个案例来分析当子类继承父类,创建子类对象时,内存中到底发生了什么?提示:当子类对象创建好后,建立查找的关系package com.whwedu.extend_;/*** 讲解继承的本质*/public class ExtendsTheory {public static void main(String[] args) {Son son = new Son();//内存的布局//?-> 这时请大家注意,要按照查找关系来返回信息//(1) 首先看子类是否有该属性//(2) 如果子类有这个属性,并且可以访问,则返回信息//(3) 如果子类没有这个属性,就看父类有没有这个属性(如果父类有该属性,并且可以访问,就返回信息..)//(4) 如果父类没有就按照(3)的规则,继续找上级父类,直到 Object... System.out.println(son.name);//返回就是大头儿子//System.out.println(son.age);//返回的就是 39//System.out.println(son.getAge());//返回的就是 39System.out.println(son.hobby);//返回的就是旅游}}class GrandPa {//爷类String name = "大头爷爷";String hobby = "旅游";}class Father extends GrandPa {//父类String name = "大头爸爸";private int age = 39;public int getAge() {return age;}}class Son extends Father {//子类String name = "大头儿子";}
子类创建的内存布局
8.5.6 案例分析
8.6 super 关键字
8.6.1基本介绍
super 代表父类的引用,用于访问父类的属性、方法、构造器
8.6.2基本语法
8.6.3 super 给编程带来的便利/细节
8.6.4 super 和 this 的比较
8.7 方法重写/覆盖(override)
8.7.1基本介绍
8.7.2 注意事项和使用细节
方法重写也叫方法覆盖,需要满足下面的条件
8.7.3 对方法的重写和重载做一个比较
8.8 面向对象编程-多态
8.8.1 多[多种]态[状态]基本介绍
方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承基础之上的。
8.8.2 多态的具体体
方法的多态
重写和重载就体现多态
对象的多态 (核心,困难,重点)
多态的前提是:两个对象(类)存在继承关系
8.8.3 多态的向上转型和向下转型
向上转型 向上转型package com.whwedu.poly_.detail_;public class Animal {String name = "动物";int age = 10;public void sleep(){System.out.println("睡");}public void run(){System.out.println("跑");}public void eat(){System.out.println("吃");}public void show(){System.out.println("hello,你好");}}package com.whwedu.poly_.detail_;public class Cat extends Animal {public void eat(){//方法重写System.out.println("猫吃鱼");}public void catchMouse(){//Cat 特有方法System.out.println("猫抓老鼠");}}package com.whwedu.poly_.detail_;public class Dog extends Animal {//Dog 是 Animal 的子类}package com.whwedu.poly_.detail_;public class PolyDetail {public static void main(String[] args) {//向上转型: 父类的引用指向了子类的对象//语法:父类类型引用名 = new 子类类型();Animal animal = new Cat();Object obj = new Cat();//可以吗? 可以 Object 也是 Cat 的父类//向上转型调用方法的规则如下://(1)可以调用父类中的所有成员(需遵守访问权限)//(2)但是不能调用子类的特有的成员//(#)因为在编译阶段,能调用哪些成员,是由编译类型来决定的//animal.catchMouse();错误//(4)最终运行效果看子类(运行类型)的具体实现, 即调用方法时,按照从子类(运行类型)开始查找方法//,然后调用,规则我前面我们讲的方法调用规则一致。animal.eat();//猫吃鱼.. animal.run();//跑animal.show();//hello,你好animal.sleep();//睡//我希望,可以调用 Cat 的 catchMouse 方法//多态的向下转型//(1)语法:子类类型 引用名 =(子类类型)父类引用;//问一个问题? cat 的编译类型 Cat,运行类型是 CatCat cat = (Cat) animal;cat.catchMouse();//猫抓老鼠//(2)要求父类的引用必须指向的是当前目标类型的对象Dog dog = (Dog) animal; //可以吗? 不可以System.out.println("ok~~");}}
8.8.4 属性没有重写之说!属性的值看编译类型
public class PolyDetail02 {public static void main(String[] args) {//属性没有重写之说!属性的值看编译类型Base base = new Sub();//向上转型System.out.println(base.count);// ? 看编译类型 10Sub sub = new Sub();System.out.println(sub.count);//? 20}}class Base {//父类int count = 10;//属性}class Sub extends Base {//子类int count = 20;//属性}
8.8.5 instanceOf 比较操作符
instanceOf 比较操作符,用于判断对象的运行类型是否为 XX 类型或 XX 类型的子类型。
public class PolyDetail03 {public static void main(String[] args) {BB bb = new BB();System.out.println(bb instanceof BB);// trueSystem.out.println(bb instanceof AA);// true//aa 编译类型 AA, 运行类型是 BB//BB 是 AA 子类AA aa = new BB();System.out.println(aa instanceof AA);// trueSystem.out.println(aa instanceof BB);// trueObject obj = new Object();System.out.println(obj instanceof AA);//falseString str = "hello";//System.out.println(str instanceof AA);//直接报错,字符串和AA没有任何关系System.out.println(str instanceof Object);//true}}class AA {} //父类class BB extends AA{} //子类
8.8.6 java 的动态绑定机制(非常非常重要.)
Java 重要特性: 动态绑定机制
再看一种情况:
public class DynamicBinding {public static void main(String[] args) {//a 的编译类型 A, 运行类型 BA a = new B();//向上转型System.out.println(a.sum());// 30System.out.println(a.sum1());// 20}}class A {//父类public int i = 10;//动态绑定机制:public int sum() {//父类 sum()return getI() + 10;//20 +10}public int sum1() {//父类 sum1()return i + 10;//10 + 10}public int getI() {//父类 getIreturn i;}}class B extends A {//子类public int i = 20;public int getI() {//子类 getI()return i;}}
8.8.7 多态的应用
多态数组
数组的定义类型为父类类型,里面保存的实际元素类型为子类类型
应用实例:现有一个继承结构如下:要求创建 1 个 Person 对象、2 个 Student 对象和 2 个 Teacher 对象, 统一放在数组 中,并调用每个对象 say 方法.
应用实例升级:如何调用子类特有的方法,比如 Teacher 有一个 teach , Student 有一个 study 怎么调用?
代码:
package com.whwedu.houserent.view;class Person {private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String say() {//返回名字和年龄return name + "\t" + age;}}class Student extends Person {private double score;public Student(String name, int age, double score) {super(name, age);this.score = score;}public double getScore() {return score;}public void setScore(double score) {this.score = score;}//重写父类 say@Overridepublic String say() {return "学生 " + super.say() + " score=" + score;}//特有的方法public void study() {System.out.println("学生 " + getName() + " 正在学 java...");}}class Teacher extends Person {private double salary;public Teacher(String name, int age, double salary) {super(name, age);this.salary = salary;}public double getSalary() {return salary;}public void setSalary(double salary) {this.salary = salary;}//写重写父类的 say 方法@Overridepublic String say() {return "老师 " + super.say() + " salary=" + salary;}//特有方法public void teach() {System.out.println("老师 " + getName() + " 正在讲 java 课程...");}}public class PloyArray {public static void main(String[] args) {//应用实例:现有一个继承结构如下:要求创建 1 个 Person 对象、// 2 个 Student 对象和 2 个 Teacher 对象, 统一放在数组中,并调用每个对象 say 方法Person[] persons = new Person[5];persons[0] = new Person("jack", 20);persons[1] = new Student("mary", 18, 100);persons[2] = new Student("smith", 19, 30.1);persons[3] = new Teacher("scott", 30, 20000);persons[4] = new Teacher("king", 50, 25000);for (int i = 0; i < persons.length; i++) {//老师提示: person[i] 编译类型是 Person ,运行类型是是根据实际情况有 JVM 来判断System.out.println(persons[i].say());//动态绑定机制//这里大家聪明. 使用 类型判断 + 向下转型.if (persons[i] instanceof Student) {//判断 person[i] 的运行类型是不是 StudentStudent student = (Student) persons[i];//向下转型student.study();//小伙伴也可以使用一条语句 ((Student)persons[i]).study();} else if (persons[i] instanceof Teacher) {Teacher teacher = (Teacher) persons[i];teacher.teach();} else if (persons[i] instanceof Person) {//System.out.println("你的类型有误, 请自己检查...");} else {System.out.println("你的类型有误, 请自己检查...");}}}}
多态参数
方法定义的形参类型为父类类型,实参类型允许为子类类型
package com.whwedu.houserent.view;public class Employee {private String name;private double salary;public Employee(String name, double salary) {this.name = name;this.salary = salary;}//得到年工资的方法public double getAnnual() {return 12 * salary;}public String getName() {return name;}public void setName(String name) {this.name = name;}public double getSalary() {return salary;}public void setSalary(double salary) {this.salary = salary;}}package com.whwedu.houserent.view;public class Manager extends Employee {private double bonus;public Manager(String name, double salary, double bonus) {super(name, salary);this.bonus = bonus;}public double getBonus() {return bonus;}public void setBonus(double bonus) {this.bonus = bonus;}public void manage() {System.out.println("经理 " + getName() + " is managing");}//重写获取年薪方法@Overridepublic double getAnnual() {return super.getAnnual() + bonus;}}package com.whwedu.houserent.view;public class Worker extends Employee {public Worker(String name, double salary) {super(name, salary);}public void work() {System.out.println("普通员工 " + getName() + " is working");}@Overridepublic double getAnnual() {//因为普通员工没有其它收入,则直接调用父类方法return super.getAnnual();}}package com.whwedu.houserent.view;public class PloyParameter {public static void main(String[] args) {Worker tom = new Worker("tom", 2500);Manager milan = new Manager("milan", 5000, 200000);PloyParameter ployParameter = new PloyParameter();ployParameter.showEmpAnnual(tom);ployParameter.showEmpAnnual(milan);ployParameter.testWork(tom);ployParameter.testWork(milan);}//showEmpAnnual(Employee e)//实现获取任何员工对象的年工资,并在 main 方法中调用该方法 [e.getAnnual()]public void showEmpAnnual(Employee e) {System.out.println(e.getAnnual());//动态绑定机制.}//添加一个方法,testWork,如果是普通员工,则调用 work 方法,如果是经理,则调用 manage 方法public void testWork (Employee e){if (e instanceof Worker) {((Worker) e).work();//有向下转型操作} else if (e instanceof Manager) {((Manager) e).manage();//有向下转型操作} else {System.out.println("不做处理...");}}}
8.9 Object 类详解
8.9.1 equals方法
==和 equals 的对比 [面试题]
== 是一个比较运算符
== :既可以判断基本类型,又可以判断引用类型== :如果判断基本类型,判断的是值是否相等。实例: int i = 10; doublt d = 10.0;== :如果判断引用类型,判断的是地址是否相等,即判定是不是同一对象。equals :是Object类中的方法,只能判断引用类型。(可以查看Jdk源码)默认判断的是地址是否相等,子类中往往重写该方法,用于判断内容是否相等。比如:Integer,String【看看String 和 Integer的 equals 源代码】
8.9.2 hashCode 方法
几个小结:
提高具有哈希结构的容器的效率!两个引用,如果指向的是同一个对象,则哈希值肯定是一样的!两个引用,如果指向的是不同对象,则哈希值是不一样的哈希值主要根据地址号来的!, 不能完全将哈希值等价于地址
8.9.3 toString 方法
基本介绍
默认返回:全类名+@+哈希值的十六进制,【查看 Object 的 toString 方法】
子类往往重写 toString 方法,用于返回对象的属性信息
重写 toString 方法,打印对象或拼接对象时,都会自动调用该对象的 toString 形式
当直接输出一个对象时,toString 方法会被默认的调用, 比如 System.out.println(monster); 就会默认调用 monster.toString()
8.9.4 finalize 方法
当对象被回收时,系统自动调用该对象的 finalize 方法。子类可以重写该方法,做一些释放资源的操作什么时候被回收:当某个对象没有任何引用时,则 jvm 就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来 销毁该对象,在销毁该对象前,会先调用 finalize方法垃圾回收机制的调用,是由系统来决定(即有自己的 GC 算法), 也可以通过 System.gc() 主动触发垃圾回收机制8.10 断点调试(debug)
8.10.1 一个实际需求
8.10.2 断点调试介绍
8.10.3 断点调试的快捷键
F7(跳入) F8(跳过) shift+F8(跳出) F9(resume,执行到下一个断点)