记录自己看渡一教育免费java基础课的学习过程。
面向过程的编程思想 VS 面向对象的编程思想:
-
面向过程的编程思想
解决问题的时候按照一定的过程(流程)钟点工—> 大象装冰箱 总共分几步
1.开门 2.大象装里面 3.关门以过程为本–复用–增加了很多冗余
大段的过程 拆分成小段 ------到底是哪一个实体来做的 引入面向对象思想。 -
面向对象的编程思想
解决问题的时候按照现实生活中的规律来考虑问题
考虑在这个问题的过程中 有几个实体参与进来
理解为 实体动作动作的支配者 没有实体动作就发生不了人 冰箱 大象
分析每一类个体都有什么特点 做了哪些事情
大象:特点 大 体重很重
冰箱: 特点 有门 容积
人:特点 能做事情 做了哪些事情呢 ? 开冰箱门 装大象 关门
一、面向对象之属性
- 类
人类
抽象笼统的概念,描述一类事物 ,肯定是具有相同的特征行为
人类有名字 有年龄 有性别-----静态描述特征(特征)-----属性
人类能吃饭 能说话 能学习-----动态动作行为(做事)-----方法
- 对象
具体的人,人类中的一个具体的人, 郑中拓
郑中拓这个具体的人 有名字 有年龄 有性别
能吃饭,能说话, 能学习
-
在现实生活中 对象是先有的 总结出来的概念(类) 后产生的
-
在计算机中利用面向对象的思想来做事
需要先自己定义(描述)一个类(型)
想要做事情 需要在描述的类中创建一个具体的个体(对象)出来
个体(对象)来 做事如何在计算机中创建(描述)一个类
1.先创建一个类class
2.类的里面 利用属性或方法去描述这个类
3.创建一个当前类的对象 让对象调用属性/方法做事
对象的创建在哪儿都可以创建类中的属性:
属性–静态描述特点
必要的组成部分
修饰符 数据类型 属性名字 [= 值];
值可有可无。
例子:
创建一个Person类的属性:
public class Person {
//这个文件是在计算机内 画的一张图纸
//描述计算机里的人类长成什么样子
//属性--静态描述特点
// 必要的组成部分
// 修饰符 数据类型 属性名字 [= 值];
public String name;//全局变量
public int age;
public String sex;//
//*方法--描述可以做什么事情(动作)
//对象的创建在哪儿都可以
}
创建并使用对象
创建对象:
Person p = new Person();
//p的小人 也有自己的名字 年龄 性别 有没有值???
//通过对象. 去调用属性 存值/取值
//属性是有默认值 name==null age==0 sex==null
对象的使用:
//存值,赋值
p.name = "郑中拓";
p.age = 18;
p.sex = "男";
//取值
System.out.println(p.name+"今年"+p.age+"岁,性别是"+p.sex);
创建并使用对象的完整代码:
public class Test {
//这个类没有什么现实意义
//只是为了将主方法写在这里
public static void main(String[] args){
//想要在这里使用一个人 来执行操作
//创建一个人类的对象 找一个空间来存储
Person p = new Person();
//p的小人 也有自己的名字 年龄 性别 有没有值???
//通过对象. 去调用属性 存值/取值
//属性是有默认值 name==null age==0 sex==null
p.name = "郑中拓";
p.age = 18;
p.sex = "男";
Person p1 = new Person();
//p1另外的一个小人 也有自己的 名字 年龄 性别
p1.name = "姬成小姐姐";
p1.age = 16;
p1.sex = "女";
System.out.println(p.name+"今年"+p.age+"岁,性别是"+p.sex);
System.out.println(p1.name+"今年"+p1.age+"岁,性别是"+p1.sex);
}
}
补充:如果将Person p1 = new Person();
改为Person p1 = p;
会发现两次的输出结果是一样的,都是姬成小姐姐…。原因如下:
Person p = new Person();Person p 看到了new,在堆内存中申请一块空间,装成和方法区中的Person的类一样。堆内存中的东西给栈内存怎么给?实际上,Person P中存的是一个地址,指向堆内存中的东西。三角形那一部分。
p.name = “郑中拓”;
p.age = 18;
p.sex = “男”;
在堆内存中添加属性(黑色字):
name = “郑中拓”;
age = 18;
sex = “男”;
Person p1 = new Person();
和刚才上面的描述一模一样,五角星的那一部分。
Person p1 = p;
绿色那一部分,如果写p,那么首先绿色那一部分没有。
把三角号复制给了p1,p1也是三角号,指向p所指向的空间。
没有new就不会产生新的堆内存空间。
所以p1.name修改了,等于相当于改掉了p原来的name。绿色部分。所以原来的郑中拓等的信息就被覆盖掉了。
二、面向对象之方法
类中的方法---->做一件事情
- 方法的定义:
权限修饰符 [特征修饰符] 返回值类型 方法名字 (参数列表) [抛出异常] [{
方法体
}]
[ ]表示可有可无,所以必须有的为:
权限修饰符 返回值类型 方法名字 (参数列表) {
}
参数列表:有参数就有没有参数就没有
- 无参数无返回值
- 无参数有返回值
- 有参数无返回值
- 有参数有返回值
人类有名字 有年龄 有性别----属性
人类能吃饭 能说话 能学习----方法
-
方法的调用
首先需要新建一个对象Person p = new Person();
然后通过对象调用方法p.eat();
-
上述四种方法的使用例子
方法:可以理解为方法是做了一件事情
返回值:可以理解为返回值是这件事情做完了 留下的一个结果
参数:可以理解为参数是做事情之前 必须提供的条件
无参数无返回值的方法的例子:
//主函数Test类中
//无参数 无返回值
public class Test {
public static void main(String[] args){
Person p = new Person();
p.eat();//方法的调用
}
}
无参数有返回值的方法的例子:
必须有return,否则报错
Person类中:
//设计一个方法 用来告诉别人我的名字 "郑中拓"
//若方法的设计规定了返回值类型 方法内必须通过return关键字返回一个值
public String tellName(){
System.out.println("你们问我叫什么呀?勉强告诉你们一下");
return "郑中拓";//只有一个
}
主函数Test类中:
//无参数 无返回值
public class Test {
public static void main(String[] args){
Person p = new Person();
String myName = p.tellName();//定义一个变量接收方法的返回值 当然,你也可以选择不接受那个返回值,但是一般需要接收的
System.out.println("接收到了tellName方法的返回值:"+myName);
}
}
有参数无返回值例子:
调用方法时必须传入参数;
参数个数随意
Person类中:
//设计一个新的吃饭方法
//描述人类可以做吃饭饭这件事情
public void chiFanFan(int count,String something){
System.out.println("吃了"+count+"碗"+something);
}
主函数Test类中:
public class Test {
public static void main(String[] args){
Person p = new Person();
p.chiFanFan(2,"面条");//传递参数
}
}
有参数有返回值例子:
设计一个方法
1.需不需要提供条件
2.需不需要给别人留下什么结果
Person类中:
// 需要提供条件 钱
//需要返回值 买到的饮料 名字
public String buyDrink(int money){
if(money>5){
return "红牛";
}else{
return "矿泉水";
}
}
主函数Test类中:
public class Test {
public static void main(String[] args){
Person p = new Person();
String drinkName = p.buyDrink(10);
System.out.println("买到了一瓶:"+drinkName);
}
}
三、形参实参
形参可以理解为是方法执行时的临时变量空间 x
实参可以理解为是方法调用时传递进去的参数 a
方法调用时会将实参的内容传递给形参
如果内容是基本类型 传递的 是值 形参改变 实参不变
如果内容是引用类型 传递的 是引用 形参改变 实参跟着改变
- 基本类型
public class Test {
public int changeNum(int x){
System.out.println("方法执行开始:"+x);//1
x = 10;//修改传递进来的值
System.out.println("方法执行最终:"+x);//10
// return x ;//返回值 将x临时的变量空间内的值(值 引用)返回出来
}
//每一个类中不是必须包含主方法的
//主方法不属于任何一个类--主方法属于虚拟机
public static void main(String[] args){
Test t = new Test();
int a=1;
t.changeNum(a);
System.out.println("方法执行完毕,main方法中a的值:"+a);//1
}
}
上面代码解析图分析:
方法区中加载一个类,类中有一个方法。
Test t = new Test();在堆内存中开辟一块空间,和方法区中的类长得一模一样。栈内存中有一个Test t ,指向堆内存中的地址。
int a=1; 常量池中复制一个1给a
1.方法存在哪里? 堆内存的对象空间内
2.方法在哪里执行的? 栈内存中开辟一块临时的方法执行空间
t.changeNum(a); //调用方法 让方法执行一遍。
栈内存开辟临时空间(红色),临时的执行changeNum方法。
方法执行开始的时候,定义一个临时变量空间,int x。空间中的值由a中把传进了进来。所以x的值就有了,是1。
然后常量池中拿出来一个10 ,装到x中,x由1变为10。方法执行完毕,红色空间消失。
System.out.println(“方法执行完毕,main方法中a的值:”+a);
最后又输出a,发现a中的变量空间还在。a=1这个只是给临时变量空间用一下,原来的1仍然存在,所以最后输出的结果还是1。
如果我想要让a的值 , 跟着方法内部的形参改变?看图中绿色。
如果想把10留下来,怎么办呢?在方法即将结束的时候,把这个10扔出来,利用return把这个值留下来。
return x ;//返回值 将x临时的变量空间内的值(值 引用)返回出来。main中得写:a = t.changeNum(a);把return的结果在装到a空间。
- 引用类型
public class Test {
public void changeArray(int[] x){
System.out.println("方法执行开始:"+x[0]);//1
x[0] = 10;//修改数组x的第一个位置元素
System.out.println("方法执行最终:"+x[0]);//10
}
//每一个类中不是必须包含主方法的
//主方法不属于任何一个类--主方法属于虚拟机
public static void main(String[] args){
//0.加载类模板的过程
Test t = new Test();//创建对象
int[] a = new int[]{1,2,3};
t.changeArray(a);
//方法存在堆内存的对象空间里 方法执行在栈内存中的临时空间
//调用方法时将a的值传递给了x int[] x = a; 传递过来的就是一个 引用
System.out.println("方法执行完毕,main方法中a数组的第一个值:"+a[0]);//10
}
}
int[] a = new int[]{1,2,3}; 堆内存中又开辟了一个新的数组空间
t.changeArray(a); 方法存在堆内存的对象空间里 方法执行在栈内存中的临时空间。栈内存中开辟临时空间(红色)。
int[] x,临时空间创建一个变量,
调用方法时将a的值传递给了x int[] x = a; 传递过来的就是一个 引用(地址)。
方法将x[0]变为了10。红色部分消失。a数组中的五角星还存在,所指向的空间还在,但是[0]的值已经发生了变化。
习题
0. 设计一个方法 用来画星星 倒三角
行数不确定 方向也不确定
public class Group {
public void drawstar(int line,boolean f){
for(int i=1;i<line+1;i++) {
if (f != true) { //true左对齐 false右对齐
for (int j = 1; j < i; j++) {
System.out.print(" ");
}
}
for(int j=i;j<line;j++){
System.out.print("*");
}
System.out.println();
}
public int[][] change(int[] a,int[] b){
int[] temp =int[] a;
}
}
}
- 设计一个方法 用来交换两个数组元素 a{1,2,3,4} b{5,6,7,8}
方式一:
//方式一不需要返回值
public class Demo {
//设计一个方法 用来交换两个数组的元素
// 方法本身是否需要参数及返回值 需要参数 提供两个数组 返回值 暂时先不要
public int[][] changeTwoArray(int[] a,int[] b){
//2.交换数组中的元素
//方式一 将两个数组内的元素对应位置互换
for(int i=0;i<a.length;i++){//每一次找到一个数组中的元素 跟另一个数组对应位置
int x = a[i];
a[i] = b[i];
b[i] = x;
}
//方式一的设计问题在于
// 用循环的方式挨个交换数组内的元素 性能比较慢
// 交换的时候需要保证两个数组的长度是一致的
}
public static void main(String[] args){
//创建一个Demo对象
Demo d = new Demo();
//用来交换两个数组元素 a{1,2,3,4} b{5,6,7,8}
//1.先有两个数组
int[] x = {1,2,3,4};
int[] y = {5,6,7,8};
//2.调用demo中的changeTwoArray方法
int[][] value = d.changeTwoArray(x,y);
//3.验证一下看一看
for(int v:x){
System.out.println(v);
}
System.out.println("-----------");
for(int v:y){
System.out.println(v);
}
}
}
方式一理解图:
int[][] value = d.changeTwoArray(x,y);理解图中红色部分。把方法拿到栈内存中执行。栈内存中开辟临时空间,方法中先丁定义两个临时变量a和b。a和b的值由x,y传入。a找到堆内存中三角,b找到堆内存中的五角星。将值互换以后,方法执行完毕,红色部分全部消失,但是堆内存的值已经改变了。
方式二:
//方式二必须需要返回值
public class Demo {
public int[][] changeTwoArray(int[] a,int[] b){
//方式二 将两个数组的地址引用直接互换
int[] temp = a;
a = b;
b = temp;
int[][] result = {a,b};
return result;
}
public static void main(String[] args){
//创建一个Demo对象
Demo d = new Demo();
//用来交换两个数组元素 a{1,2,3,4} b{5,6,7,8}
//1.先有两个数组
int[] x = {1,2,3,4};
int[] y = {5,6,7,8};
//2.调用demo中的changeTwoArray方法
int[][] value = d.changeTwoArray(x,y);
x = value[0]; //把value的值拆开
y = value[1];
//3.验证一下看一看
for(int v:x){
System.out.println(v);
}
System.out.println("-----------");
for(int v:y){
System.out.println(v);
}
}
}
方式二理解图:
方法放到栈内存中执行,栈内存开辟临时空间。首先定义两个临时变量空间,值由调用方法时x和y传入。方法中定义一个新的temp临时空间,三个临时空间折腾了一遍,导致a中存的变为了五角星,b中存的是三角形。然后方法执行完毕,蓝色和红色部分全部消失。发现(黑色部分)x指向的值没有发生变化,y指向的值也没有发生变化。所以需要返回值。但是返回值只能返回一个,那么怎么办呢?考虑新建一个新的小数组,用来装数组的数组才可以装得下。int[][] result = {a,b};
return result;
- 设计一个方法 用来交换一个数组(头尾互换)
是否需要参数:需要,因为要提供数组
返回值:不需要 ,因为输出的还是自己本身
//*2.设计一个方法 用来交换一个数组(头尾互换)
//是否需要参数及返回值 需要提供一个数组 不需要返回值
public void changeArrayElements(int[] array){
//2.数组内部的元素头尾对应互换
for(int i=0;i<array.length/2;i++){
int temp = array[i];
array[i] = array[array.length-1-i];
array[array.length-1-i] = temp;
}
}
主函数中代码:
//交换数组内部元素
TestFunctions tf = new TestFunctions();
//1.有一个数组
int[] x = new int[]{1,2,3,4,5,6,7,8,9};
//2.利用tf对象调用方法执行操作
tf.changeArrayElements(x);//x--->array
//3.验证看一看结果
for(int v:x){
System.out.println(v);
理解图如下:
红色图是不需要返回值的情况
蓝色是加了返回值 return array
但是实际上不要return,就可以了。
传进去的三角和传出去的三角是一个的时候,就不需要返回值了。如果是引用类型,传进去是一个,传出来的还是一个,那我就不用return去接了。
x已经发生变化了,所以不需要再拿一个return值去接了。
- 设计一个方法 用来寻找数组中的极值(最大值 或 最小值)
//3.设计一个方法 用来寻找数组中的极值(最大值 或 最小值)
//是否需要参数及返回值 需要提供一个数组 需要提供一个值(最大 最小) 返回值肯定需要一个值
public int findMaxOrMinNum(int[] array,boolean flag){//flag==true最大值 flag==false最小值
//2.找一个变量
int temp = array[0];
//3.利用遍历数组的方式挨个与max比较
for(int i=1;i<array.length;i++){
if(flag && array[i]>temp){//找寻最大值
temp = array[i];
}else if(!flag && array[i]<temp){//找寻最小值
temp = array[i];
}
}
//3.将找到的值返回
return temp;
}
- 设计一个方法 用来找寻给定的元素是否在数组内存在(Scanner输入一个)
//是否需要参数及返回值 需要提供一个数组 需要一个目标元素 返回值告诉你是否找到啦
// 方法设计了返回值类型 就必须给返回值 虽然你的逻辑通过,认为一定会有一个返回值,但是一但程序在没有执行之前可能没有看到明确的返回值,就会报错。 编译检测的悲观性原则
public String isExist(int[] array,int element){
//循环方式找寻是否存在
//boolean flag=false;
String result = "对不起 您要的值在数组中没有";
for(int i=0;i<array.length;i++){
if(array[i]==element){
result = "恭喜您 您要的值在数组中存在";
//flag=true;
break;
}
}
/*
if(flag==false){
result="数组中不存在";
} */
return result;
}
- 设计一个方法 用来合并两个数组
//5.设计一个方法 用来合并两个数组
// 是否需要参数 需要提供两个数组 需要返回一个大的数组
public int[] mergeArray(int[] a,int[] b){
//创建一个新的数组
int[] newArray = new int[a.length+b.length];
//分别将a和b数组的元素存入新数组内
for(int i=0;i<a.length;i++){
newArray[i] = a[i];
}
for(int i=0;i<b.length;i++){
newArray[a.length+i] = b[i];
}
//将新数组返回
return newArray;
}
- 设计一个方法 用来将一个数组按照最大值位置拆分
//6.设计一个方法 用来将一个数组按照最大值位置拆分
//需要提供一个大的数组 需要返回值二维数组
public int[][] splitArray(int[] array){// 1 2 3 9 4 5
//找寻最大值索引位置
int max = array[0];//记录最大值
int index = 0;//记录最大值的索引位置
for(int i=1;i<array.length;i++){
if(array[i]>max){
max = array[i];
index = i;
}
}
//通过找寻到的index判定数组拆分后的前后长度
int[] newa = new int[index];
int[] newb = new int[array.length-index-1];
//分别将两个小数组填满
for(int i=0;i<newa.length;i++){
newa[i] = array[i];
}
for(int i=0;i<newb.length;i++){
newb[i] = array[(index+1)+i];
}
//将两个新的小数组一起返回
return new int[][]{newa,newb};
}
- 设计一个方法 用来去掉数组中的0元素
//7.设计一个方法 用来去掉数组中的0元素
//需要提供参数一个数组 需要提供删除的元素是什么 返回值 一个新的数组
public int[] removeElementFromArray(int[] array,int element){
//找寻原数组中去掉被删除元素后的长度
int count = 0;//记录非删除元素的个数
for(int i=0;i<array.length;i++){
if(array[i]!=element){
count++;
}
}
//通过找到的count创建一个新数组
int[] newArray = new int[count];
int index = 0;//控制新数组的索引变化
//将原来数组中非删除的元素存入新数组中
for(int i=0;i<array.length;i++){
if(array[i]!=0){
newArray[index++] = array[i];
}
}
//将新数组返回
return newArray;
}
- 设计一个方法 用来存储给定范围内的素数(2-100)
//8.设计一个方法 用来存储给定范围内的素数(2-100) 素数在自然数之内
//是否需要提供条件 begin end 返回值一个装满了素数的数组
public int[] findPrimeNum(int begin,int end){
if(begin<0 || end<0){
System.out.println("素数没有负数 不给你找啦");
return null;//自定义一个异常 认为规定的一种不正常的现象
}
if(begin>=end){
System.out.println("您提供的范围有误 begin应该比end要小");
return null;//自定义一个异常 认为规定的一种不正常的现象
}
//创建一个足够长的数组
int[] array = new int[(end-begin)/2];
int index = 0;//记录新数组的索引变化 同时记录个数
for(int num=begin;num<=end;num++){
boolean b = false;//标记
for(int i=2;i<=num/2;i++){
if(num%i==0){
b = true;
break;
}
}
if(!b){
array[index++] = num;
}
}
//将数组后面的多余的0去掉
int[] primeArray = new int[index];
for(int i=0;i<primeArray.length;i++){
primeArray[i] = array[i];
}
array = null;
return primeArray;
}
- 设计一个方法 用来给数组元素排序(冒泡排序算法)
既能升序又能降序
//9.设计一个方法 给数组进行排序(既能升序又能降序)
//是否需要提供条件---数组 提供一个排序的规则boolean 返回值---不用
//flag==true升序排列 flag==false降序排列
public void orderArray(int[] array,boolean flag){
for(int i=1;i<array.length;i++){//控制执行的轮次---数组的长度
for(int j=array.length-1;j>=i;j--){//控制比较4次
//什么情况下可以进行元素的互换
// (flag==true && array[j]<array[j-1]) || (flag==false && array[j]>array[j-1])
if((flag==true && array[j]<array[j-1]) || (flag==false && array[j]>array[j-1])){
int temp = array[j];
array[j] = array[j-1];
array[j-1] = temp;
}
}
}
}
- 设计一个方法 用来实现用户登录认证(二维数组当作小数据库)
//*10.设计一个方法 用来实现用户登录认证(二维数组当作小数据库)
//是否需要条件? 需要提供账号名和密码 需要返回值 登录成功与否的结果
//简单的输出和返回值不一样,简单的输出,我们不能把值拿走,不能进行后续的操作
//但是如果是返回值,我们得到这个值,然后进行后续的操作
//比如那这个返回值,来判断是否进入系统或者重新输入用户名和密码。
//1.需要有小数据库---存储用户真实的账号和密码
private String[][] userBox = {{"郑中拓","123456"},{"渡一教育","666666"},{"Java","888"}};
public String login(String user,String password){
//4.进行校验
String result = "用户名或密码错误";
for(int i=0;i<userBox.length;i++){
if(userBox[i][0].equals(user)){
if(userBox[i][1].equals(password)){
result = "登录成功";
}
break;
}
}
return result;
}
四、重载
-
概念:一个类中的一组方法,相同的方法名字 ,不同的参数列表 ,这样的一组方法构成了方法重载
参数列表的不同体现在哪里?
参数的个数
参数的类型
参数的顺序 -
作用:为了让使用者便于记忆与调用,只需要记录一个名字,执行不同的操作 。比如println,因为有了重载,我们只需要记录一个println,就可以了,否则可能需要printlnBoolean;printlnString…所以可以看出重载的好处了。
-
自己也可以设计方法重载
调用方法的时候 首先通过方法名字定位方法
如果方法名字有一致 可以通过参数的数据类型定位方法
如果没有与传递参数类型一致的方法 可以找一个参数类型可以进行转化(自动)
public class TestOverload {
public void test(){
System.out.println("执行了test方法没有携带参数");
}
public void test(boolean b){
System.out.println("执行了test方法带boolean参数"+b);
}
public void test(int i){
System.out.println("执行了test方法带int参数"+i);
}
public void test(String s){
System.out.println("执行了test方法带String参数"+s);
}
public static void main(String[] args){
//1.创建对象
TestOverload to = new TestOverload();
to.test('a');
}
}//结果为:97 走的是int类型的那个函数
// to.test('a');如果改为to.test((char)97)就可以输出a了
但是如果用以下的函数:
public void test(char c){
System.out.println("执行了test方法带char参数"+c);
}
那么输出的结果会是,a。
- JDK1.5版本之后 出现了一个新的写法
- int… x 动态参数列表,类型固定,个数可以动态 0–n都可以
- x本质上就是一个数组 ,有length属性,有[index]
- 动态参数列表的方法 不能 与相同意义的数组类型的方法构成方法重载 本质是一样的
public void test(int...x){//本质数组 int[] x = {1,2,3,4,5,6};
System.out.println("执行了test方法携带动态列表");
for(int i=0;i<x.length;i++){
System.out.println(x[i]);
}
}
public void test(int[] array){ //报错!!!!
}
public void test(int[][] array){ //这个就不会报错,因为最上面的是一维数组 这个是二维数组 意义不同 可以重载
}
- 动态参数列表的方法 可以不传参数,相当于0个。
数组的方法 必须传递参数 - 动态参数列表在方法的参数中只能存在一份儿,且必须放置在方法参数的末尾。
public void test(int a,int...x)
不会报错。
public void test(int...x,int a)
报错。