0008方法传递机制、重载、可变参数、对象数组、封装、构造器

001方法的参数传递机制-------------------------------------------------------------

 

/*
方法的参数传递机制:
实参-->形参

 

(1)形参是基本数据类型
实参赋值给形参的是数据值,形参值的修改不影响实参,因为实参是“copy,复制”了一份数据值给形参
(2)形参是引用数据类型
*/

/*

class Test02_PassParamValue{
public static void main(String[] args){
int x = 1;
int y = 2;
//本类同级别的方法调用
swap(x,y);

System.out.println("x = " + x + ",y = " + y);
}
//public static修饰符
public static void swap(int a,int b){
System.out.println("a = " + a + ",b = " + b);
int temp = a;
a = b;
b = temp;
System.out.println("a = " + a + ",b = " + b);
}
}


方法的参数传递机制:
实参-->形参

(1)形参是基本数据类型
实参赋值给形参的是数据值,形参值的修改不影响实参,因为实参是“copy,复制”了一份数据值给形参

 

 


(2)形参是引用数据类型
实参赋值给形参的是对象的地址值,如果形参修改了对象的属性值,那么实参对象的属性值也会修改。
*/

class Test02_PassParamValue_2{
public static void main(String[] args){
Circle yuan = new Circle();
yuan.radius = 1.0;

doubleRadius(yuan);

System.out.println("半径:" + yuan.radius);
}
//方法的功能:可以把c这个圆对象的半径,变为原来的2倍
public static void doubleRadius(Circle c){
c.radius *= 2;
}

}
class Circle{
double radius;
}

-----------------面试时的陷阱-----------------------------------------------------------

/*
面试时的陷阱:
当形参是引用数据类型,实参给形参地址值之后,
形参修改了地址值,那么和实参就无关了
*/

实际上,就是你new了一个新的对象之后,之前的地址就不是这个了,那么你所改的都不存在了,相当于没有调用这个方法,因为这个方法改变不了任何东西

 

------------------方法的重载------------------------------------------------

 

 

/*
方法的重载:
在同一个类中,出现了两个或多个的方法名称相同,形参列表不同,称为方法的重载。
形参列表不同:形参的个数、数据类型不同
方法的重载和返回值类型无关。

为什么要有方法的重载?或者换句话说,为什么要声明多个方法名称相同呢?
(1)方法名代表方法的功能,这几个方法的功能是一样的,例如:都是找最大值
(2)为了调用者的方便,功能相同的方法取名一样的话,对于调用者来说就减少了学习和记忆的成本
*/

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

System.out.println( max(1,2));
}
//写一个方法,可以找2个整数的最大值
/*
public static int max(int a, int b){
return a>b ? a : b;
}
*/
//方法重载时,不去看返回值类型是否一致,只看方法名和形参列表
public static double max(int a,int b){
return 0.0;
}
//写一个方法,可以找2给小数的最大值
public static double max(double a, double b){
return a>b ? a : b;
}
//写一个方法,可以找3个整数的最大值
public static int max(int a, int b, int c){
int max = a > b ? a : b;
max = max > c ? max : c;
return max;
}
}

 

 

 -----------命令行参数--------------------------------------------------

/*
命令行参数:(了解)
给main方法传的实参,叫做命令行参数
格式:
java main所在的类名 实参1 实参2 ...
例如:
java Test04_CommandParam hello java atguigu
*/

/*
因为main也是一个有参无返回值的方法,那么如何给main传参数呢?
*/

【注意】命令行参数虽然简单但是不会的人也是完全不会

下面说一下,操作办法,非常简单

只要在命令行输入 比如:  java 类名(包含主方法的类) hello java atguigu

 

 ----------------------可变参数---------------------------------------

/*
可变参数:JDK1.5之后引入的
形参列表中出现了“数据类型... 形参名”形式的形参,就是可变参数。
包含可变参数的方法的调用原则:
(1)可变参数的形参部分,可以传入0~n个对应类型的实参,也可以传入对应类型的数组对象
(2)非可变参数的形参部分,原来该怎么传,现在还怎么传

可变参数的声明的原则:
(1)一个方法只能包含一个可变参数
(2)可变参数必须是形参列表的最后一个
参数:
(1)形参
(2)实参
(3)命令行参数
(4)可变参数
(5)...
*/

其实C#里面也有可变参数,叫做params,java中也有这个概念,概念相同,关键字不同,写法稍微有点变化

1、可变参数当数组使用

 

 

 完整代码:

 

class test08_6VarParam可变参数{
/*
因为main也是一个有参无返回值的方法,那么如何给main传参数呢?
*/
//java test08_5CommandParam hello java atguigu;
public static void main(String[]args){
//args是形参,是String[]类型,是一个一维数组
for(int i=0;i<args.length;i++){
System.out.println("第"+(i+1)+"个参数的值是:"+args[i]);
}
//开始可变参数部分
System.out.println("这里面的数的和" + sum(2,4,1));

System.out.println("这里面的最大值是" + max(2,4,6,7,8));

int [] arr1 = new int[0];
System.out.println("0个元素的累加和:" + sum(arr1));//可变参数部分,传入了对应类型的数组对象

int[] arr2 = {1,2,3,4,5};
System.out.println("5个元素的累加和:" + sum(arr2));//可变参数部分,传入了对应类型的数组对象

System.out.println("0个元素的累加和:"+sum());//可变参数部分,传入0个实参int的值

//注意点
System.out.println("1个元素的最大值:"+max(5));//5赋值给了非可变参数的形参
System.out.println("5个元素的最大值"+max(5,1,5,6,8));//第1个5赋值给了非可变参数的形参,剩下的给了可变参数

//错误写法示例(如果要运行无错,请注释这段)
System.out.println("1个元素的最大值:"+max());////错误的,因为max方法有一个非可变参数的形参,必须传值
}

//声明一个方法,功能:可以求两个整数的和
public static int sum(int a,int b){
return a + b;
}
//声明一个方法,功能:可以求0-n个整数的和
public static int sum(int...nums){
//1、nums当成数组用
int sum=0;
for(int i=0;i<nums.length;i++){
sum+=nums[i]; //实际上可变参数是一个一维数组
}
return sum;
}
//如果是以前的做法
public static int sum2(int[]nums){
int sum=0;
for(int i=0;i<nums.length;i++){
sum+=nums[i]; //实际上可变参数是一个一维数组
}
return sum;
}
//声明一个方法,功能:可以求1-n个整数的最大值
//int num1 就是非可变参数部分
//int... nums是可变参数
public static int max(int num1,int...nums){
int max=num1;
for(int i=0;i<nums.length;i++){
if(nums[i]>max){
max=nums[i];
}
}
return max;
}
}代码截图

 

 错误示例的运行效果(看我代码里面写了,错误示例)

 --------什么叫做方法签名---------------------------

方法 = 方法签名/方法头 + 方法体

方法签名:【修饰符】 返回值类型 方法名(【形参列表】)
方法体:{}

 

-------------------- 练习:声明一个数学工具类,包含如下方法-------------------------------

/*
(1)可以求0~n字符串的拼接结果
(2)可以求1~n整数的乘积

*/

 

-----------成员变量和局部变量--------------------------------------------

/*
变量的分类:
1、成员变量:今天讨论的都是非静态的成员变量
2、局部变量

(1)声明的位置不同
成员变量:
	类中方法外
	类{
		【修饰符】 数据类型  成员变量;
	}
局部变量
	方法中:(1)形参,也是局部变量(2)方法体{}中声明的变量
	后面可能还要加上代码块中。
	类{
		【修饰符】 返回值类型  方法名(【形参列表】){
			数据类型  局部变量;
		}
	}
(2)运行时在内存中的位置也不相同
成员变量:堆
局部变量:栈
(3)初始化不同
成员变量:
	如果没有初始化,有默认值
局部变量:
	如果没有初始化,就会报错,不能用

(4)生命周期
成员变量:
	随着对象的创建而分配,随着对象被垃圾回收器回收而结束
局部变量:
	方法被调用,开始分配,方法执行结束就结束

(5)可用的修饰符
成员变量:有很多修饰符,具体哪些后面再讲
局部变量:唯一的一个就是final,具体什么意思再讲
*/
class Test07_Variable{
	public static void main(String[] args){//args是局部变量
		String ming = "张三";//ming局部变量
		int nian = 23;//nian局部变量
		
		Student s1 = new Student();//s1局部变量
		s1.name = ming;//s1.name不是在这里声明的,只是使用它
		s1.age = nian;
	}
}
class Student{
	String name;//name是成员变量
	int age;//age是成员变量
	
	void set(String n, int a){//n和a是局部变量
		name = n;
		age = a;
	}
}

  

 

 

 -------数组对象----------------------

/*
数组是用来存一组数,这组数可以是基本数据类型,也可以是引用数据类型
例如:
int[] arr; 存了一组整数
char[] arr;存了一组单字符

String[] arr; 存了一组字符串对象
Student[] arr; 存了一组学生对象
Circle[] arr; 存了一组圆对象

当我们数组中存储了一组对象时,那么我们称为对象数组。
*/

 

 1 class test08_9ObjectArray数组对象{
 2     public static void main(String[]args){//args是局部变量
 3         //要用一个数组,存储5个圆对象,半径分别为1-5
 4         //(1)声明一个数组
 5         //数组的元素的类型是Circle
 6         Circle [] arr=new Circle[5];    //这new是创建数组对象
 7         
 8         //(2)为数组元素赋值
 9         for(int i=0;i<arr.length;i++){
10             //元素:数组名[下标]
11             //arr[i].radius=i+1;
12             arr[i]=new Circle();     //创建圆对象
13             arr[i].radius=1+i;
14             
15         }
16         //(3)、遍历数组
17         for(int i=0;i<arr.length;i++){
18             //现在的数组的元素arr[i]就是一个圆对象,既然是圆对象,就可以调用圆的属性和方法
19             arr[i].printInfo();
20             
21         }
22     }
23 }
24 class Circle{
25     double radius;
26     double getArea(){
27         return 3.14*radius*radius;
28     }
29     void printInfo(){
30         System.out.println("半径"+radius+",面积:"+getArea());
31     }
32 }

 

 

---数组对象练习---------------------------------------------------------

 

/*
练习2
(1)声明一个学生类Student,包含姓名name和成绩score属性
(2)在测试类TestStudentArray中创建一个长度为3的学生数组
(3)从键盘输入为学生对象的姓名和成绩属性赋值
(4)遍历显示学生信息
(5)使用冒泡排序对数组按照学生成绩从低到高排序
(6)再次遍历显示学生信息
*/

 1 class test08_10数组对象实例{
 2     public static void main(String[]args){//args是局部变量
 3         //(2)在测试类TestStudentArray中创建一个长度为3的学生数组
 4         Student[] all=new Student[3];
 5         //(3)从键盘输入为学生对象的姓名和成绩属性赋值
 6         java.util.Scanner input=new java.util.Scanner(System.in);
 7         for(int i=0;i<all.length;i++){
 8             System.out.println("请输入第"+(i+1)+"个学生的信息:");
 9             
10             //创建这个学生对象
11             all[i]=new Student();
12             System.out.print("姓名:");
13             all[i].name=input.next();
14             
15             System.out.print("成绩:");
16             all[i].score=input.nextInt();
17         }
18         //(4)遍历显示学生信息
19         System.out.println("-------遍历如下-------------");
20         for(int i=0;i<all.length;i++){
21             System.out.print(all[i].name+":");
22             System.out.println(all[i].score);
23         }
24         //(5)使用冒泡排序对数组按照学生成绩从低到高排序
25         for(int i=0;i<all.length;i++){
26             for(int j=0;j<all.length-1;j++){
27                 if(all[j].score<all[j+1].score){
28                     //如果第1个小于第2个就不替换,否则就替换他们
29                     
30                 }else{
31                     Student temp=new Student();
32                     temp=all[j];
33                     all[j]=all[j+1];
34                     all[j+1]=temp;
35                 }
36             }
37         }
38         System.out.println("-------从低到高排序后遍历如下-------------");
39         for(int i=0;i<all.length;i++){
40             System.out.print(all[i].name+":");
41             System.out.println(all[i].score);
42         }
43     }
44 }
45 //(1)声明一个学生类Student,包含姓名name和成绩score属性
46 class Student{
47     String name;
48     int score;
49     void printInfo(){
50         System.out.println("姓名:" + name + ",成绩:" + score);
51     }
52     String getInfo(){
53         return "姓名:"+name+",成绩:"+score;
54     }
55 }

----------面向对象的基本特征之一 封装-------------------------------------

面向对象的基本特征:
(1)封装
(2)继承
(3)多态

一、封装

1、封装的意义:
(1)隐藏实现细节
(2)安全

2、封装的类型:
(1)属性的封装、方法的封装等
(2)组件的封装
(3)系统的封装

3、封装的实现,靠权限修饰符来控制可见的范围。
权限修饰符:
(1)可见范围
本类 本包 其他包子类 任意位置
private: √ × × ×
缺省/省略: √ √ × ×
protected: √ √ √ ×
public √ √ √ √

(2)哪些可以加权限修饰符
类、属性、方法、构造器、内部类

(3)分别可以加什么权限修饰符
类:缺省或public
如果类前面有public,那么必须与源文件名相同
属性:四种都可以
方法:四种都可以

4、属性的封装
大多数情况下,属性都是private
如果属性私有化了,我们会提供get/set方法
get/set的标准写法:
public void set属性名(数据类型 形参名){
属性名 = 形参名;
}
public 属性的数据类型 get属性名(){
return 属性名;
}

5、方法的封装
大多数情况下,方法都是public

*/

 

class test08_11Encapsulation封面向对象的基本特征_封装{
    public static void main(String[]args){
        //1、创建对象
        Circle c1=new Circle();
        //2、为属性赋值
        //c1.radius=1.2;//这种方式是错误的
        c1.setRadius(2);
        
        System.out.println("半径:"+c1.getRadius());
    }
}
class Circle{
    private double radius;    //仅限与本类中访问
    
    //radius属性的set方法,用于在其它类中修改radius的值
    public void setRadius(double r){
        if(r > 0){//使得赋值可控
            radius=r;
        }
    }
    //radius 属性的get方法,用于在其它类中获取radius的值
    public double getRadius(){
        return radius;
    }
}

练习:

/*
1、声明学生类,
(1)有属性:姓名,年龄,成绩,并且私有化,
(2)提供公共的get/set。
(3)提供getInfo()方法,返回学生对象的信息
2、在测试中用set方法赋值,用getInfo()返回学生信息
*/

 1 class test08_12getset封装练习{
 2     public static void main(String[]args){
 3         Studnet stu=new Studnet();
 4         stu.setName("张三丰");
 5         stu.setAge(80);
 6         stu.setScore(100);
 7         
 8         System.out.println(stu.getInfo());
 9     }
10 }
11 
12 class Studnet{
13     private String name;
14     private int age;
15     private double score;
16     //提供公共的get/set。
17     public String getName(){
18         return name;
19     }
20     public void setName(String n){
21         if(n!=""){
22             name=n;
23         }
24     }
25     
26     public void setAge(int a){
27         age = a;
28     }
29     public int getAge(){
30         return age;
31     }
32 
33     public void setScore(double s){
34         score = s;
35     }
36     public double getScore(){
37         return score;
38     }
39      
40      public String getInfo(){
41          return "姓名:"+name+"; 年龄"+age+";成绩:"+score;
42      }
43 }

------------------------构造器---------------------------------------------------------------

 

构造器就是C#中的构造方法(想一想是不是)

/*
类的第三个组成部分:
构造器,也称为构造方法,因为(1)它长的像方法(2)它编译后是一个实例初始化方法

1、构造器的作用
(1)构造对象,创建对象
和new一起使用,每次调用它就是在创建新的对象
(2)可以在创建对象的同时,给属性赋值

2、构造器的特点
(1)所有类都有构造器
(2)如果一个类没有显式声明构造器,那么编译器将会自动生成一个默认的无参构造
(3)如果一个类显式声明了构造器,那么编译器将不会自动生成默认的无参构造了
(4)构造器的名称必须与类名相同
(5)构造器没有返回值类型,也不写void
(6)构造器可以重载

重载:在同一个类中,方法名相同,形参列表不同的两个和多个方法,和返回值类型无关

3、构造器的语法结构
【修饰符】 类名(){

}
【修饰符】 类名(形参列表){

}

回忆:
java.util.Scanner input = new java.util.Scanner(System.in);//调用的是有参构造
int num = input.nextInt();//从键盘输入一个整数
java.util.Random rand = new java.util.Random();//调用的是无参构造
int num = random.nextInt(10);//产生一个[0,10)的整数
*/

 1 class test08_13Constructor构造器{
 2     public static void main(String[]args){
 3         //创建对象 
 4         //类名 对象名 =new 类名();
 5         Circle c=new Circle();
 6         Circle cc=new Circle(1.2);//调用的是有参构造函数  1.2给半径赋值,在创建对象的时候同时给属性赋值了
 7         
 8         cc.setRadius(2.5);//创建对象之后,修改属性值用的
 9         cc.printInfo();
10         
11         Circle c2=new Circle();//先创建对象,不给半径赋值
12         c2.setRadius(3.6);
13         c2.printInfo();
14     }
15 }
16 class Circle{
17     private double radius;
18     //double r:构造器的形参列表
19     public Circle(double r){//有参构造
20         radius=r;//给班级赋值
21     }
22     
23     public Circle(){//无参构造函数
24         
25     }
26     
27     public void printInfo(){
28         System.out.println("半径:"+radius);
29     }
30     
31     public void setRadius(double r){
32         radius=r;
33     }
34 }

我们习惯上:
类{
属性列表;

构造器列表;

方法列表;
}
*/

 

 

----------注意点-:有参构造器里面赋值操作不能漏掉-----------------

看下面这段构造器代码

 1 /*
 2 1、声明学生类,
 3 (1)有属性:姓名,年龄,成绩,并且私有化,
 4 (2)提供有参和无参构造
 5 (3)提供公共的get/set。
 6 (4)提供getInfo()方法,返回学生对象的信息
 7 2、在测试中
 8 (1)用有参和无参构造分别创建对象
 9 (2)用set方法修改属性值
10 (3)用getInfo()返回学生信息
11 
12 习惯上:
13 类{
14     属性列表;
15     
16     构造器列表;
17     
18     方法列表;
19 }
20 */
21 class test08_14Exer5构造器练习{
22     public static void main(String[]args){
23         //1、无参构造函数创建对象
24         Student s1=new Student();
25         //s1.setName="张三";//错误的
26         s1.setName("张三");
27         //s1.name="111";//也是错误的,因为private是私有的,访问不到
28         s1.setAge(23);
29         s1.setScore(89);
30         System.out.println(s1.getInfo());
31         
32         //2、有参数构造函数创建对象
33         Student s2=new Student("李四",24,80);////相对来说有参有时候好像还方便一些
34         System.out.println(s2.getInfo());
35         s2.setScore(74);//修改成绩的值
36         System.out.println(s2.getInfo());
37     }
38 }
39 class Student{
40     private String name;
41     private int age;
42     private double score;
43     
44     //创建无参和有参的构造函数
45     public Student(){
46         
47     }
48     
49     public Student(String n,int a,double s){    //特别注意这里,
50         name=n;                                    //有参构造函数(有参构造器)里面要赋值操作
51         age=a;
52         score=s;
53     }
54     
55     //提供公共的get/set。
56     public String getName(){
57         return name;
58     }
59     public void setName( String s){
60         name=s;
61     }
62     
63     public int getAge(){
64         return age;
65     }
66     public void setAge( int a){
67         age=a;
68     }
69     
70     public double getScore(){
71         return score;
72     }
73     public void setScore( double s){
74         score=s;
75     }
76     
77     public String getInfo(){
78         return "姓名:" + name + ",年龄:" + age +",成绩:" +score;
79     }
80 }

 

posted @ 2020-07-22 07:32  猛兽总是独行  阅读(380)  评论(0编辑  收藏  举报