重新开始学Java——方法

  • Post author:
  • Post category:java


方法是类或对象的行为特征的抽象:它描述的是这个方法能干什么(具有操作性);如传 入什么参数、 完成什么操作、 返回什么结果;方法类似于过去结构化程序设计中的函 数,比如 C 语言里的函数、 C++里的函数。

  • 方法的定义:

    	[ 修饰符 ] 方法返回值类型 方法名 (形参列表){
    		//方法体
    	}
    

    例如:

    	public class Monkey {
    		/**
    		 * 修饰符 返回什么类型 方法名称(传入什么参数) {
    		 * 这个方法 负责做什么
    		 * 如果返回类型不是void ,则需要 用 return 语句来带回来一个值
    		 ( 类型是明确的)
    		 * }
    		 */
    		public int add( int a , int b ){
    			int c = a + b ;
    			return c ; // 返回 c ( c 是int 类型,其中存储的值是 a 与 b 的和 );
    		}
    		public void subtract ( int a , int b){
    			int c = a - b ;
    	// return c; //如果返回类型是 void ,则不需要返回数据
    			System.out.println(a + " - " + b + " = "+c);
    		}
    	}
    

    当然,这里是自己写的东西,以下是官方文档中的描述:

    	Here is an example of a typical method declaration:
    
    	public double calculateAnswer(double wingSpan, int numberOfEngines,
    								  double length, double grossTons) {
    		//do the calculation here
    	}
    	The only required elements of a method declaration are the method's return type, name, a pair of parentheses, (), and a body between braces, {}.
    

    这里说的就是 : 一个方法的定义仅仅需要 方法的返回类型、方法的名字、一对小括号和在花括号之间的身体 这些元素 组成。

  • 方法的命名

    	Although a method name can be any legal identifier, code conventions restrict method names. By convention, method names should be a verb in lowercase or a multi-word name that begins with a verb in lowercase, followed by adjectives, nouns, etc. In multi-word names, the first letter of each of the second and following words should be capitalized. Here are some examples:
    
    	run
    	runFast
    	getBackground
    	getFinalData
    	compareTo
    	setX
    	isEmpty
    
    	Typically, a method has a unique name within its class. However, a method might have the same name as other methods due to method overloading.
    
    

    以上是官方文档中所说的,虽然方法名可以是任何法定标识符,但代码约定限制方法名。按照惯例,方法名应该是小写的动词或以小写的动词开头的多单词名,后面跟着形容词、名词等。在多单词名中,每个单词的首字母和后面的单词都应该大写。

  • 方法的属主

    	Java 里的方法必须有属主,也就是说这个方法是属于谁的。
    
    	方法不能独立存在, 一般定义在类体内
    		方法只能定义在类体内
    		方法不可以定义在方法内(语法要求)
    	从逻辑上看, 方法或者属于类, 或者属于对象
    	被 static 修饰的方法属于类, 它将被该类的所有对象所共享
    	没有被 static 修饰的方法, 只能属于类的某一对象(各对象不共享)
    	方法不能独立运行, 必须通过类或者对象调用它
    	不可能直接使用诸如 rename() 直接运行
    	只能通过 类名.方法名 或者 对象名.方法名 的形式调用方法
    
    	被 static 修饰的方法, 可以通过 类名.方法名 和 对象名.方法名 调用
    	没有被 static 修饰的方法, 只能通过对 象名.方法名 调用
    

    例子:

    	public class Sheep {
        // 实例属性,属于具体的某个实例所拥有
        public String name;
        // 静态属性(类属性):这个属性的拥有者是当前这个类,而不是具体的某个个体
        public static String school;// 静态属性被所有实例 共享
        // 实例方法,基于那个实例去调用,就表现那个实例的行为特征 比如:s2.showName();
        public void showName(){
            // this 是当前类 的一个实例,与汉语中的 “我” 对应
            System.out.println("My name is "+ this.name);
        }
        // 静态方法(类方法):这个方法的拥有者是当前这个类,而不是 具体 的 某个 个体
        public static void showSchool(){
            System.out.println("My school id " + school);
        }
    }
    

    访问的例子:

    	public class TestSheep{
    		public static void main(String[] args) {
    			// 访问静态属性(类属性)用 “类名.属性名” 的形式访问
    			// Sheep 的 school
    			Sheep.school = "大肥羊学校";
    			// 创建Sheep类的对象(实例)
    			Sheep s1 = new Sheep();// 实例化 一个Sheep 对象
    			s1.name = "喜羊羊";
    			s1.showName(); // s1 的 showName()
    			// The static method showSchool() from the type Sheep should be
    			accessed in a static way
    			// 那个静态属性 Sheep.school 应该访问 用静态的方式
    			// Sheep类中的静态属性 school 应该用 静态的方式 去访问
    			s1.showSchool();;// 应该用“类名.属性名”的形式访问
    			Sheep s2 = new Sheep();
    			s2.name = "懒羊羊";
    			s2.showName();// s2 的 showName()
    		}
    	}
    
  • 参数传递机制

    • 形参和实参
    	形参 - 形式上的参数
    		在方法名之后, 紧跟的小括号内部, Java 里管它叫形参列表 
    		形参是相对于实参而言的
    		对于一个不被调用的方法来说, 它的参数就是个摆设, 不具实际意义
    		只有当调用一个方法, 传入了具体的值, 这个参数才有意义
    	实参 - 实际的参数
    		调用一个方法时, 给方法传入的具体的参数的值
    		这个具体的参数的值是具有实际意义的
    		Java 里的方法只有被调用, 传入参数, 方法体才有意义
    
    • 基本数据类型的参数传递机制
    	public class Dog {
    		/**
    		 * 注意:这里的int a 和 int b 都是该方法的形式参数
    		 */
    		public int add(int a,int b){
    			int c = a+b;
    			return c;
    		}
    		// 相当于 i = 100
    		public void increment(int i) {
    			System.out.println("i = "+ i);
    			i++;
    			System.out.println("i = "+ i);
    		}
    	}
    

    测试函数:

    	public class TestDog {
    		public static void main(String[] args) {
    			int a = 100;
    			int b = 200;
    			// Dog.class 会加载,创建这个类型的对象(只要运行,就会被加载)
    			Dog wangcai = new Dog();
    			// 注意,这里的 a 和 b 是 add 方法执行时传入的实参
    			int c = wangcai.add( a, b );
    			System.out.println("运算结果是:"+ c);
    			System.out.println("*********************************************");
    			int i =100;
    			System.out.println("在i increment执行之前 i = "+ i);
    		// 将 i 作为实参 传递给 wangcai 引用的对象的 increment 方法
    		// 注意:这里仅仅是将 i 变量存储的值 传递个 increment 方法
    		// 这个时候可以举例子:身份证原件与身份证复印件的关系
    			wangcai.increment(i);// int i = i; // 意思是 将前面声明的i 变量的值 赋给 形参 i
    			System.out.println("在i increment执行之后 i = "+ i);// 说明方法内部的 i 与 声明的i 不是同一个i
    		}
    	}
    
    • 引用类型的参数传递
    	// 声明一个类
    	public class Person {
    		public String name; // 姓名
    		public char gender;// 性别
    		// 对参数 传入的 对象 P 实施变性操作(男--->女;女--->男)
    		public void changeGender(Person p) {
    			// 顺着 p 变量内存储的地址,找到堆区域中的对象
    			if (p.gender == '男') {
    				p.gender = '女';
    			} else if (p.gender == '女') {
    				p.gender = '男';
    			}
    		}
    	}
    

    测试方法:

    	public class TestPerson {
    		public static void main(String[] args) {
    			// 创建一个大夫,用来给“顾客”做手术
    			Person doctor = new Person();
    			doctor.gender = '男';
    			doctor.name = "朱天佑";
    			Person customer = new Person();
    			customer.gender = '男';
    			customer.name = "金星";
    			System.out.println(customer.gender);
    			System.out.println(customer);
    			// doctor 的 changeGender 方法 为 customer 变性
    			doctor.changeGender( customer );
    			System.out.println(customer.gender);
    		}
    	}
    

    数据结果:

    	男
    	methods.Person@15db9742
    	女
    

    图解:

    这里是声明了两个 Person 对象,一个是 doctor,另一个是 customer,分别存放在main 方法的栈中,分别指向了堆中存放的东西,但是在调用 doctor.changeGender 的方法的时候,就会产生一个 doctor.changeGender 的方法栈。

    通过doctor.changeGender( customer );这一行代码,就会将main方法栈中的customer地址传到changeGender的方法栈中,并赋予了相应的值,也就是customer的地址。那么在changeGender的方法栈中,对应的P也就是有了相应的地址,那么通过相应的地址就可以找到在堆中存放的数据。

    那么通过 changeGender 方法就可以将 customer 的 gender 的值改变掉。

  • 方法的返回值

    	返回值,一般理解为方法被调用、执行完成后,向它的调用者返回的一个数值或对象。
    
    	谁调用了方法,方法就把其返回值返回给谁,在哪里调用了方法,方法就把其返回值返	回到哪里。就是相当于,你早上买早餐,你调用买早餐这个方法,那么这个方法就给你	返回了你所需要的早餐,那么这个早餐是你需要的么?是的,因为你是调用买早餐这个方法。
    
    	Java 是强类型语言,因此必须指定返回类型。函数是可以有返回值的,也是可	以没有的,当有返回值的时候,那么返回什么类型就写什么类型,如果不需要返回值的时候,那么就是void关键字,表示不需要返回,如果不需要返回,那么也可以写return,只不过 return 后边什么都不写就可以了。当方法需要返回的时候,一般使用 return 语句,方法运行中,一旦遇到 return 语句便立即返回,方法执行到 return 语句就结束运行(调用)。
    
  • 方法的重载

    • 方法的重载定义:
    	同一个类中有两个或两个以上方法同名不同参的方法,称为方法重载。注意,重载发生在:本类的方法之间(前提条件),有继承关系的,还有继承来的方法与本类方法之间。
    
    • 重载发生的条件:
    	同名:至少有两个方法同名(也可以是两个以上);
    	不同参:同名的方法中,其参数类型、个数、顺序至少有一个不同
    	可选的条件:方法的返回类型可以不相同,方法的修饰符可以不相同。
    

    例如 :

    	public class TraversalArray {
    		public static void main(String[] args) {
    			int[] array = {1,4,68,1234,0,89};
    			traversal( array );
    		}
    		public static void traversal(short[] array) {
    			for (int i = 0; i < array.length; i++) {
    				System.out.println(array[i]);
    			}
    		}
    		public static void traversal(int[] array) {
    			for (int i = 0; i < array.length; i++) {
    				System.out.println(array[i]);
    			}
    		}
    		public static void traversal(byte[] array) {
    			for (int i = 0; i < array.length; i++) {
    				System.out.println(array[i]);
    			}
    		}
    		public static void traversal(long[] array) {
    			for (int i = 0; i < array.length; i++) {
    				System.out.println(array[i]);
    			}
    		}
    		public static void traversal(float[] array) {
    			for (int i = 0; i < array.length; i++) {
    				System.out.println(array[i]);
    			}
    		}
    		public static void traversal(double[] array) {
    			for (int i = 0; i < array.length; i++) {
    				System.out.println(array[i]);
    			}
    		}
    		public static void traversal(char[] array) {
    			for (int i = 0; i < array.length; i++) {
    				System.out.println(array[i]);
    			}
    		}
    		public static void traversal(boolean[] array) {
    			for (int i = 0; i < array.length; i++) {
    				System.out.println(array[i]);
    			}
    		}
    	}
    

    那么在这里需要注意 : 使用方法重载的时候,可能会降低代码的阅读性。(Overloaded methods should be used sparingly, as they can make code much less readable.)

  • 可变长参数 JDK 1.5 以后, 允许定义形参长度可变的参数,即允许为方法指定数量不确定的形参。 具体格式如下:

    	[ 修饰符 ] 方法返回值类型 方法名 ( 其它形参, 形参类型... 形参名){
    		//方法体
    	}
    

    解释:

    	形如 形参类型... 形参名 的参数叫做可变长参数
    
    	注意其中的三个 .
    		可变长参数必须放在整个参数列表的最后边
    
    	下面的写法是错误的:
    		[ 修饰符 ] 方法返回值类型 方法名 ( 形参类型... 形参名 , 其它形参 ) {
    			//方法体
    		}
    
    	一个方法中至多只能有一个可变长参数!
    
    

    举例说明:

    	/**
    	* 可变长参数,是指一个方法的实参个数是可以变化的,根据需要传入参数
    	* 可变长参数 在同一个方法的参数列表中,至多出现一次,并且必须放在所有参
    	数的最后边
    	*/
    	public class ChangeParameter {
    		// 当作一个"数组"来对待
    		public static int add(int... a){
    		// 就算什么都没有传入,这个数组也是存在的只是它的长度是0而已
    		int sum = 0;
    		for (int i = 0; i < a.length; i++) {
    			sum+=a[i];
    		}
    		 return sum;
    		}
    		public static void main(String[] args) {
    			int sum1 = add();
    			int sum2 = add(1,2,3,4);
    			System.out.println(sum1+sum2);
    		}
    	}
    

    注意 : 如果在可变长参数的方法中没有传入任何参数,那也没有什么影响,也就是说数组的长度为0。

转载于:https://my.oschina.net/lujiapeng/blog/2249976