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 }