JavaRush /Java 博客 /Random-ZH /方法签名

方法签名

已在 Random-ZH 群组中发布
你好!您已经掌握了使用字段和方法创建自己的类。今天我们就详细说说方法。当然,我们在讲座中不止一次这样做过,但我们主要讨论的是一般性的观点。今天,我们将逐字分析这些方法 - 我们将找出它们的组成部分、创建它们的选项以及如何管理所有这些:) 让我们开始吧!方法签名 - 1

方法签名

所有描述方法的代码称为方法声明。方法签名包括按特定顺序排列的方法名称和参数类型。广告的总体外观可以描述如下:
модификатор доступа, тип возвращаемого значения, Name метода(список параметров) {
    // тело метода
}
我们以类的几个方法的声明为例Dog
public class Dog {

   String name;

   public Dog(String name) {
       this.name = name;
   }

   public static void main(String[] args) {
       Dog max = new Dog("Max");
       max.woof();

   }

   public void woof() {
       System.out.println("Собака по имени " + name + " говорит \"Гав-гав!\"");
   }

   public void run(int meters) {
       System.out.println("Собака по имени " + name + " пробежала " + meters + " метров!");
   }

   public String getName() {
       return name;
   }
}

1. 访问修饰符

访问修饰符始终列在最前面。 所有类方法Dog均由修饰符指定public。也就是说,我们可以从任何其他类调用它们:
public class Main {

   public static void main(String[] args) {

       Dog butch = new Dog("Бутч");
       butch.run(100);
   }

}
正如您所看到的,类方法Dog可以在类中轻松访问Main。这要归功于修饰符public。Java 中还有其他修饰符,但并非所有修饰符都允许您在另一个类中使用方法。我们将在其他讲座中讨论它们。最重要的是记住修饰符的作用:其他类中该方法的可用性/不可访问性:)

2.static关键字

其中一种方法Dog,即main()由关键字指示static。如果存在,则必须在访问修饰符之后指定。还记得在之前的讲座中我们讨论过静态类变量吗?当应用于方法时,这个词具有大致相同的含义。如果一个方法被指定为static,这意味着它可以在不引用特定类对象的情况下使用。事实上,要main()在类中运行静态方法,Dog您不需要创建实例Dog;它无需创建实例即可运行。如果这个方法不是静态的,那么要使用它,我们需要首先创建一个对象。

3.返回值。

如果我们的方法必须返回某些内容,那么我们将指示返回值的类型。这可以在 getter 的示例中看到getName()
public String getName() {
   return name;
}
它返回一个类型的对象String。如果该方法不返回任何内容,则指定关键字而不是 type void,如方法中所示woof()
public void woof() {
   System.out.println("Собака по имени " + name + " говорит \"Гав-гав!\"");
}

同名方法

在某些情况下,我们的程序需要多个选项来确定方法的工作方式。我们为什么不创造自己的人工智能呢?Amazon 有 Alexa,Yandex 有 Alice,那为什么我们会更差呢?:) 在有关钢铁侠的电影中,托尼·斯塔克创造了自己杰出的人工智能 - JARVIS 让我们向这个精彩的角色致敬,并以他的名字命名我们的人工智能:)我们必须教贾维斯的第一件事是——向进入房间的人打招呼(如果如此伟大的智慧最终被证明是不礼貌的,那就太奇怪了)。
public class Jarvis {

   public void sayHi(String name) {
       System.out.println("Good evening, " + name + ", How are you doing?");
   }

   public static void main(String[] args) {
       Jarvis jarvis = new Jarvis();
       jarvis.sayHi("Tony Stark");
   }
}
控制台输出:

Добрый вечер, Тони Старк, How ваши дела?
伟大的!贾维斯知道如何迎接进来的人。当然,最常见的是他的主人——托尼·斯塔克。但他可能不会一个人来!我们的方法sayHi()只接受一个参数作为输入。因此,他只能向其中一位来者打招呼,而忽略另一位。不太礼貌,同意吗?:/ 在这种情况下,为了解决问题,我们可以简单地在类中编写两个同名但参数不同的方法:
public class Jarvis {

   public void sayHi(String firstGuest) {
       System.out.println("Good evening, " + firstGuest + ", How are you doing?");
   }

   public void sayHi(String firstGuest, String secondGuest) {
       System.out.println("Good evening, " + firstGuest + ", " + secondGuest + ", How are you doing?");
   }

}
这称为方法重载。重载使我们的计划更加灵活并适应不同的工作选择。让我们检查一下它是如何工作的:
public class Jarvis {

   public void sayHi(String firstGuest) {
       System.out.println("Good evening, " + firstGuest + ", How are you doing?");
   }

   public void sayHi(String firstGuest, String secondGuest) {
       System.out.println("Good evening, " + firstGuest + ", " + secondGuest + ", How are you doing?");
   }

   public static void main(String[] args) {
       Jarvis jarvis = new Jarvis();
       jarvis.sayHi("Tony Stark");
       jarvis.sayHi("Tony Stark", "Captain America");
   }
}
控制台输出:

Добрый вечер, Тони Старк, How ваши дела? 
Добрый вечер, Тони Старк, Капитан Америка, How ваши дела?
太棒了,两种选择都有效:)但是,我们没有解决问题!如果有三个客人怎么办?当然,我们可以再次重载该方法sayHi()以接受三位客人的名字。但也可以有 4 或 5 个,以此类推,无止境。是否有另一种方法可以教 Jarvis 使用任意数量的名称,而不需要一百万个方法重载sayHi()?:/ 当然有!否则,Java 会成为世界上最流行的编程语言吗?;)
public class Jarvis {

   public void sayHi(String...names) {

       for (String name: names) {
           System.out.println("Good evening, " + name + ", How are you doing?");
       }
   }

   public static void main(String[] args) {
       Jarvis jarvis = new Jarvis();
       jarvis.sayHi("Tony Stark");
       System.out.println();
       jarvis.sayHi("Tony Stark", "Captain America");
   }
}
作为参数传递的记录 ( String...names) 允许我们指示将一定数量的字符串传递给该方法。我们没有提前指定应该有多少个,因此我们方法的操作现在变得更加灵活:
public class Jarvis {

   public void sayHi(String...names) {

       for (String name: names) {
           System.out.println("Good evening, " + name + ", How are you doing?");
       }
   }

   public static void main(String[] args) {
       Jarvis jarvis = new Jarvis();
       jarvis.sayHi("Tony Stark", "Captain America", "Black Widow", "Hulk");
   }
}
控制台输出:

Добрый вечер, Тони Старк, How ваши дела? 
Добрый вечер, Капитан Америка, How ваши дела? 
Добрый вечер, Черная Вдова, How ваши дела? 
Добрый вечер, Халк, How ваши дела?
在该方法内部,我们循环遍历所有参数并将带有名称的现成短语输出到控制台。这里我们使用一个简化的循环for-each(你已经遇到过)。这很棒,因为写入String...names实际上意味着编译器将所有传递的参数放入数组中。因此, names您可以像使用数组一样使用变量,包括循环访问它。此外,它适用于任意数量的传输线路!两个、十个、甚至一千个——该方法对于任意数量的客人都可以可靠地工作。比对所有可能的选项进行重载要方便得多,您同意吗?:)让我们再举一个方法重载的例子。让我们向 Jarvis 添加一个方法printInfoFromDatabase()。它将把有关该人的信息从数据库打印到控制台。如果数据库表明一个人是超级英雄或超级恶棍,该信息也会显示在屏幕上:
public class Jarvis {

   public  void printInfoFromDatabase (String bio) {

       System.out.println(bio);
   }

   public void printInfoFromDatabase(String bio, boolean isEvil, String nickname) {

       System.out.println(bio);
       if (!isEvil) {
           System.out.println("Также известен How супергерой " + nickname);
       } else {
           System.out.println("Также известен How суперзлодей " + nickname);
       }
   }

   public static void main(String[] args) {
       Jarvis jarvis = new Jarvis();
       jarvis.printInfoFromDatabase("Лора Палмер. Дата рождения - 22 июля 1972, город Твин Пикс, штат Washington");
       System.out.println();
       jarvis.printInfoFromDatabase("Макс Эйзенхарт. Рост 188см, вес 86 кг.", true, "Магнето");
   }
}
结论:

Лора Палмер. Дата рождения - 22 июля 1972, город Твин Пикс, штат Washington
Макс Эйзенхарт. Рост 188см, вес 86 кг 
Также известен How суперзлодей Магнето
这就是我们的方法的工作原理,具体取决于我们传递给它的数据。 另一个重要的一点:参数的顺序很重要!假设我们的方法接受一个字符串和一个数字作为输入:
public class Man {

   public static void sayYourAge(String greeting, int age) {
       System.out.println(greeting + " " + age);
   }

   public static void main(String[] args) {

       sayYourAge("My age - ", 33);
       sayYourAge(33, "My age - "); //error!
   }
}
如果sayYourAge()类方法Man接受字符串和数字作为输入,那么这就是它们在程序中传递的顺序!如果我们以不同的顺序传递它们,编译器将抛出错误,并且该人将无法说出他的年龄。顺便说一句,我们在上一讲中介绍的构造函数也是方法!它们还可以重载(使用不同的参数集创建多个构造函数),并且对于它们来说,传递参数的顺序也非常重要。真正的方法!:)

如何调用具有相似参数的方法

大家知道,Java中有一个词null。使用它时,了解 null 既不是对象也不是数据类型非常重要。introduce()假设我们有一个 Man 类和一个声明人的姓名和年龄的方法。在这种情况下,年龄可以以文本的形式传达,也可以以数字的形式表达。
public class Man {

   public void introduce(String name, String age) {
       System.out.println("Меня зовут " + name + ", мой возраст - " + age);
   }

   public void introduce(String name, Integer age) {
       System.out.println("Меня зовут " + name + ", мой возраст - " + age);
   }

   public static void main(String[] args) {

       Man sasha = new Man();
       sasha.introduce("Sasha", "двадцать один");

       Man masha = new Man();
       masha.introduce("Мария", 32);
   }
}
我们已经熟悉重载,因此我们知道该方法两次都会按预期工作:

Меня зовут Саша, мой возраст - двадцать один 
Меня зовут Мария, мой возраст - 32 
但是如果我们传递 null 作为第二个参数,而不是字符串或数字,会发生什么?
public static void main(String[] args) {

   Man victor = new Man();
   victor.introduce("Виктор", null);//Ambiguous method call!
}
我们会得到一个编译错误!“Ambigously method call”错误被翻译为“ambiguously method call”。为什么会出现这种情况,什么是“歧义”?其实很简单。问题是,我们有该方法的两种变体:withString和 withInteger作为第二个参数。但String, 和Integer都可以为空!对于这两种类型(因为它们是引用类型),null 是默认值。这就是为什么在这种情况下编译器无法确定应该调用哪个版本的方法。解决这个问题非常简单。重点是 null 可以显式转换为特定的引用类型。因此,在调用方法时,可以在括号中指明第二个参数所需的数据类型!编译器会理解你的“提示”并调用所需的方法:
public class Man {

   public void introduce(String name, String age) {
       System.out.println("Метод с двумя строками!");
       System.out.println("Меня зовут " + name + ", мой возраст - " + age);
   }

   public void introduce(String name, Integer age) {
       System.out.println("Метод со строкой и числом!");
       System.out.println("Меня зовут " + name + ", мой возраст - " + age);
   }

   public static void main(String[] args) {

       Man victor = new Man();
       victor.introduce("Виктор", (String) null);
   }
}
结论:

Метод с двумя строками! 
Меня зовут Виктор, мой возраст - null
但如果数字参数是基元int而不是引用类型的对象Integer,则不会发生这样的错误。
public class Man {

   public void introduce(String name, String age) {
       System.out.println("Метод с двумя строками!");
       System.out.println("Меня зовут " + name + ", мой возраст - " + age);
   }

   public void introduce(String name, int age) {
       System.out.println("Метод со строкой и числом!!");
       System.out.println("Меня зовут " + name + ", мой возраст - " + age);
   }

   public static void main(String[] args) {

       Man victor = new Man();
       victor.introduce("Виктор", null);
   }
}
你猜到原因了吗?如果您猜对了,干得好:)因为基元不能等于 null。现在,编译器只有一种调用该方法的选项introduce()- 使用两行。每次调用该方法时都会处理此版本的方法。
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION