Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Механизм перегрузки методов "полиморфизм"


Автор: initmax 5.10.2009, 11:45
Пытаюсь разобраться в какой полследовательности происходит перегрузка методов.

То c чем удалось разобраться:
Перегрузка методов поддерживает полиморфизм,
 поскольку это один из способов реализации в Java концепции
 "один интерфейс, несколько методов". Для пояснения приведем
 следующие рассуждения. В тех языках, которые не поддерживают
 перегрузку методов, каждому методу должно быть присвоено уникальное имя.


1) При вызове метода компилятор проверяет объявленный тип объекта и имя метода  
например вызов x.f(args) неявный параметр х объявлен как экземпляр класса С.
Но может существовать несколько методов с именем f, поэтому компилятор нумерует все методы с общедоступным именем f в подклассе и суперклассе.

2) Вторым шагом происходит определение типов параметров указанных при вызове метода
например
f(String);
f(int);
f(char);
...
данный процесс называется разрешением перегрузки


теперь тестим


Код

import java.util.*;
import java.io.*;
import java.lang.*;


class count{

    private int odd_num=0;
    private int buff=0;

    private int countWord=0;
    private int Latin=0;


    public int test_method(int a) { return a+100; }
    public double test_method(double a) { return -100; }
    public float test_method(float a) { return -100; }
   

    public int xcount(int arr[]){

        for(int i=0; i<arr.length; i++)
        {
            if(arr[i]%2 != 0){ this.buff++; }
            if(arr[i]%2 == 0){ this.buff=0; }
            if(odd_num < buff ) { odd_num = buff; }
        }

           return odd_num;
    }


    public int xcount(char arr[]){

        for(int j=1; j<arr.length; j++)
        {

            if (java.util.regex.Pattern.matches("[^a-zA-Z ]", String.valueOf(arr[j])))
            {
            //    System.out.print(arr[j]);
                this.Latin=1;
            }

            if(arr[j] == ' ' && arr[j-1] != ' ')
            {
                if(this.Latin == 0) { this.countWord++; }
                else this.Latin=0;
            }

        }

        return this.countWord;
    }


}

  /**
 * * @author Max ITS 05v-1
 */
public class Main {
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {

       int count_word=0;
       int count_num=0;

       int arr_num[] = {1,2,3,3,3,3,4,5,8,7,7,7,7,7,2};
       char arr_sym[] = {' ',' ','h','e','l','l','o',' ','I','S','A',' ',' ',' ','w','o','w',' ','Q','S','6',' ',' ',' '};



       count Obj = new count();
       count_num = Obj.xcount(arr_num);
       count_word = Obj.xcount(arr_sym);

       System.out.println("Count word latin letter ="+count_word);
       System.out.println("Count odd number in row ="+count_num);

       byte a = 10;
       short a1 = 10;
       char a2 = '2';
       

       System.out.println("test call byte == "+Obj.test_method(a));
       System.out.println("test call short == "+Obj.test_method(a1));
       System.out.println("test call char == "+Obj.test_method(a2));

    }

}



как видно из кода одноимённые методы имеют разные типы но отличные от byte, short , char
public int test_method(int a) { return a+100; }
public double test_method(double a) { return -100; }
public float test_method(float a) { return -100; }

а при их вызове передаётся именно byte, short , char.
но вызывается каждый раз метод int.
Интуитивно чую что есть некое дерево типов, в котором int имеет повышенный приоритет
1) как работает этот механизм
2) как это называется, посоветуйет линк


З.Ы.
Есть метод который принимает вот такую строку, необходимо посчитать количество слов которые содержат только латинские буквы нижнего/верхнего регистров
char arr_sym[] = {' ',' ','h','e','l','l','o',' ','I','S','A',' ',' ',' ','w','o','w',' ','Q','S','6',' ',' ',' '};

вот решение

 
Код

 public int xcount(char arr[]){

        for(int j=1; j<arr.length; j++)
        {

            if (java.util.regex.Pattern.matches("[^a-zA-Z ]", String.valueOf(arr[j])))
            {
            //    System.out.print(arr[j]);
                this.Latin=1;
            }

            if(arr[j] == ' ' && arr[j-1] != ' ')
            {
                if(this.Latin == 0) { this.countWord++; }
                else this.Latin=0;
            }

        }

        return this.countWord;
    }


Можно ли более оптимально решить задачу?
Спасибо за внимание.


   


Автор: mbasil 5.10.2009, 12:32
Не путайте (1) перегрузку методов и  (2) полиморфизм (переопределение)

Для полиморфизма необходимо, чтобы сигнатура метода в родительском классе и классе потомке была ОДИНАКОВА (с некоторыми исключениями). Для проверки правильности одинаковой сигнатуры компилятором мы используем аннотацию @Override.

Для перегрузки методов НЕОБХОДИМО наличие  разных типов параметров или разное их количество. То есть при одинаковом названии это разные методы.


Автор: ivanovpv 5.10.2009, 13:00
Цитата(initmax @  5.10.2009,  11:45 Найти цитируемый пост)
public int test_method(int a) { return a+100; }
public double test_method(double a) { return -100; }
public float test_method(float a) { return -100; }

а при их вызове передаётся именно byte, short , char.
но вызывается каждый раз метод int.
Интуитивно чую что есть некое дерево типов, в котором int имеет повышенный приоритет
1) как работает этот механизм
2) как это называется, посоветуйет линк

 
Дело не в том, что int имеет некий повышенный приоритет, а в том, как вы вызываете test_method(). Скорее всего вызываете как
Код

System.out.println("test_method="+test_method(100));

Ну и получаете по умолчанию константу 100 с типом int. Соответственно и связывание происходит с методом test_method(int a);

Автор: initmax 5.10.2009, 14:21
Что означает "сигнатур"? в классе родителе и классе потомке должны быть одинаковы методы, только в этом случае будет организовано понятие полиморфизма ?

Автор: aleksandy 5.10.2009, 18:03
да

Автор: mbasil 5.10.2009, 19:23
Для работы полиморфизма "подписи" методов должны быть одинаковы, то есть одинаковы должны быть не только названия методов, но также количество параметров и их типы. Полиморфизм работает только в рамках наследования - "родитель-потомок". 
Перегрузка работает и в одном классе, и выполняется  при разных параметрах.
Это разные механизмы.

ЗАМЕЧАНИЕ: В полиморфных методах, в их "подписях",  могут несколько отличаться только модификатор доступа и выбрасываемые исключения.

Автор: initmax 6.10.2009, 15:58
Другими словами...?:

При наличии множества объектов обладающих общим предком и имеющим одинаковые по типу, наименованию и параметрам методы но разнящихся по реализации данных методов, используется полиформизм "многоформие".В java используется так называемое позднее связываение которое позволяет произвести вызов тела метода того или иного объекта в момент выполнения программы "на лету", получая информацию из спец. фрагментов кода об адресах методов в объектах. В С++ например для осущетсления познего связывания методы должны быть объявлены как virtual. Иначе С++ осуществляет так называемое раньее связывание, которое выполняется в момент компиляции программного кода. Генерируется компилятором вызов функции с данным именем, а линкер намертво привязывает этот вызов к абсолютному адресу кода, который предполагается к выполнению. 
Пример полиморфизма организовал на следующей задачке.

Есть некоторое множество рыбаков, каждый из которых обладает идентичными методами, но отличается внутреней реализацией данных методов. Все умеют ловить рыбу, но количество улова у каждого класса рыбака различны, т.е. реализация методов различна.



Код


import java.util.*;
import java.io.*;
import java.lang.*;

/**
 *
 * @author initmax
 */

abstract class Fisher
{
   private String Name=null;
   private String FisherClass=null;
   protected double Catch=0;
   


   public Fisher(String Name, String FisherClass) {
           this.Name = Name;
           this.FisherClass = FisherClass;
   }

   abstract public double Catch_Luck();


   public double genLuck(){    
       return (double)(1 * Math.random());  //генерируем случайное число
   }


   public String get_Name() {
       return this.Name;
   }

   public String get_FisherClass() {
       return this.FisherClass;
   }

}

//-------------------
class Amateur extends Fisher
{
     private static double MaxCatch=20;

     public Amateur(String Name)
     {
       super(Name,"Любитель"); //вызов конструктора суппер класса
     }

     public double Catch_Luck(){ //переопределение абстрактного метода
         super.Catch = (this.MaxCatch * super.genLuck());
         return super.Catch;
     }
}

//-------------------
class Profi extends Fisher
{
     private static double MaxCatch=50;

     public Profi (String Name)
     {
       super(Name,"Профессионал"); //вызов конструктора суппер класса
     }

     public double Catch_Luck(){ //переопределение абстрактного метода
         super.Catch = (this.MaxCatch * (0.5 + super.genLuck()));
         return super.Catch;
     }
}

//-------------------
class Poacher extends Fisher
{
     private static double MaxCatch=400;

     public Poacher (String Name)
     {
       super(Name,"Браконьер"); //вызов конструктора суппер класса
     }

     public double Catch_Luck(){ //переопределение абстрактного метода
         super.Catch = (1 - 0.4 * super.genLuck());
         if(super.Catch < 0.9)
         {
             return 0;
         }
         else  return MaxCatch;
     }
}

//-------------------
public class  Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {

          double catch_sum=0;
          double catch_tmp=0;

      System.out.print("\t***Welcome to fish***\n");


          Fisher arr[] = new Fisher[3];


          arr[0] = new Amateur("Берлиоз М.А.");
          arr[1] = new Profi("Воланд");
          arr[2] = new Poacher("Бездомный И.Н.");

          
          
          for(int j=0; j<3; j++)
          {
              
              for(int i=0; i<5; i++)
              {
                 catch_tmp = arr[j].Catch_Luck();
                 catch_sum += catch_tmp;

                 System.out.println("Рыбалка ["+i+"]"+"Статус - "+arr[j].get_FisherClass() + ", Ф.И.О - " + arr[j].get_Name()+", Улов = "+catch_tmp);
                 
              }
              System.out.println("Суммарный улов =="+catch_sum);
              catch_sum=0;
          
              System.out.println("\n");
              
          }

    }

}


В момент вызова методов
Код

arr[j].Catch_Luck()
arr[j].get_FisherClass() 
arr[j].get_Name()

происходит так называемое позденее связываение, которое удовлетворяет концепцию полиморфизма.

Всё ли верно? дополните/подправьте...

Спасибо за внимание.



Автор: revenforv 6.10.2009, 22:11
Можно дополнить еще, что "позднее" связывание также называется динамическим.

В http://forum.vingrad.ru/forum/topic-275017.html я уже разъяснял то, как это происходит (согласно спецификации языка Java). Буду рад, если она как-то дополнит ответ на поставленный вопрос..

Автор: initmax 7.10.2009, 08:47
Спасибо!
Интересно "ранее связывание" в java существует?

Автор: mbasil 7.10.2009, 09:02
Существует, для static и final методов.

Автор: ValerStrim 20.10.2010, 23:15
Я новичок и пытаюсь разобраться в перегрузках методов класса 
Допустим есть класс X b childX наследущий его методы...
Код:


Код

class X
  {
    public int sum(int a, int b)
    {
      return a + b;
    }
  }
 
  public class ChildX extends X
  {
    public long sum(int a, int b)
    {
      return (long)(a + b);
    }
  }



Какие из нижеприведенных перегрузок я могу юзать и это будет правильно:
public int sum(int a, long b){return 0;}
public long Sum(int a, int b){return 0;}
public int sum(int b, int a){return 0;}
public void sum(float x, float z){}
public abstract void sum(){}
Идея в том чтобы метод sum() мог возвращать значения как типа int, так и long 
Чёт не получается, помгите, разьясните, что можно, что нельзя (((
Заранее благодарю! 

Автор: Skipy 21.10.2010, 11:34
Цитата(ValerStrim @ 20.10.2010,  23:15)
Идея в том чтобы метод sum() мог возвращать значения как типа int, так и long 
Чёт не получается, помгите, разьясните, что можно, что нельзя (((

Ок, будем рассуждать логически. Пусть у Вас есть два метода:

Код
public int sum(int a, int b){
    return a + b;
}
public long sum(int a, int b){
    return (long)(a + b);
}


Ответьте на простой вопрос. Какой метод будет вызван в этом случае:

Код
sum(1,2);


P.S. Я имею полное право вызвать метод, не используя возвращаемого значения.

Автор: ValerStrim 21.10.2010, 12:14
в соседней теме объяснили, да и сам вижу что ошибка на начальном этапе.
вопрос решён.

Автор: danilka 22.10.2010, 13:23
Цитата(mbasil @  5.10.2009,  19:23 Найти цитируемый пост)
ЗАМЕЧАНИЕ: В полиморфных методах, в их "подписях",  могут несколько отличаться только модификатор доступа и выбрасываемые исключения.


Начиная с 5-й джавы в перегруженном методе возвращаемым объектом может быть не только объект класса родительского метода но и его потомок.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)