QA And Automation - Intro to Java

Part 3

Наследяване. Абстрактни Класове и Полиморфизъм.

Въпроси за загрявка

Какво представлява сигнатура на метод?

Името на метода + типовете на неговите аргументи

Въпроси за загрявка

Какво представлява method overloading?

Възможност да дефинираме няколко пъти метод с едно и също име, но различна сигнатура

Въпроси за загрявка

Какво представлява полиморфизмът?

Възможността да имаме променлива от един тип, но имплементация от различен.

Въпроси за загрявка

Какво представлява интерфейсът в Java?

Нещо, което може да съдържа само дефиниции на публични методи.

Въпроси за загрявка

Можем ли да създадем инстанция от интерфейс?

Не. Няма и да има смисъл.

Въпроси за загрявка

Интерфейсът създава ли тип?

Да. Това е важно за полиморфизмът.

Въпроси за загрявка

Кога е възможно A a = new B();?

  1. Когато A е интерфейс, а B е клас, който го имплементира
  2. Когато A е клас, който B наследява
  3. Има и още възможности, комбинации на горните 2

Въпроси за загрявка

Кое какво дава - A a = new B();

  1. A-то дефинира публичният интерфейс - методите, които може да извикаме
  2. B-то дефинира имплементацията на тези методи

Generic Types в Java

Позволяват ни да дефинираме един клас, който може да съдържа различни типове.

Това решава много фундаментален проблем.

Фундаментален проблем с контейнерит

IntegerArrayList

StringArrayList

PersonArrayList?

...

*ArrayList?

Generic Types in Java

Имаме ArrayList<Type>

И в Type слагаме каквото ни трябва според случая.

ArrayList<Integer> ns = new ArrayList<>();
ArrayList<Person> people = new ArrayList<>();

Как дефинираме Generic Types?

public class Box<T> {
	private T data;
	
	public Box(T data) {
		this.data = data;
	}

	public T getData() {
		return data;
	}
}

Как дефинираме Generic Types?

Box<Integer> intBox = new Box<Integer>(5);
Box<Panda> pandaBox = new Box<Panda>(5);

Ползват се навсякъде, особено в Collections framework-а

Интерфейсът ни позволява да дефинираме очаквано поведение.

Имаме списък от Person. Какво ни трябва, за да го сортираме?

public class Person {
  public String name;
  public String age;
}
ArrayList<Person> people = new ArrayList<>();
Collections.sort(people); // ?

По какво сортираме? Зависи от нас.

Ако Person имплементира Comperable, то може да сортираме списък от Person

public class Person implements Comperable<Person> {
  public String name;
  public String age;

  public int compareTo(Person other) {
    if(this.age == other.age) { return 1; }
    if(this.age < other.age) { return -1; }
    return 1;
  }
}

Един клас може да имплементира повече от 1 интерфейс.

 Наследяване в Java

  1. Наследяването се извършва между класове

  2. Механизъм за преизползване на код

  3. Механизъм, чрез който постигаме полиморфизъм без интерфейси

  4. Често срещан похват при разработка

 Наследяване в Java

  1. Всеки клас в Java наследява от Object.

  2. Когато наследяваме, ние взимаме наготово всички public и protected атрибути и методи.

  3. private си остава private

Object

  1. Майката на всички класове.

  2. Дефинира методи като toString(), equals() и други.
  3. Тъй като всичко наследява Object, то всичко може да бъде Object.

Всичко може да бъде Object

public static void iAcceptEverything(Object obj) {
  System.out.println(obj.toString());
}
SomeClass.iAcceptEverything(5);
SomeClass.iAcceptEverything("asdf");
SomeClass.iAcceptEverything(true);
SomeClass.iAcceptEverything(new Panda());

Пример - printArray

public class SomeClass {
  public static void printArray(Object[] arr) {
    StringBuilder b = new StringBuilder();
    b.append("[");
    for (int i = 0; i < arr.length; i++) {
      Object o = arr[i];
      b.append(o.toString());

      if (i != arr.length - 1) {
        b.append(", ");
      }
    }
    b.append("]");
    System.out.println(b.toString());
  }
}

Проблем - printArray

// this is not working, because of the primitive types
int[] a = {1, 2, 3};
SomeClass.printArray(a);
// this works well
Integer[] a = {1, 2, 3};
SomeClass.printArray(a);

Нaследяване

  1. Създаваме йерархия от класове.

  2. Винаги търсим базов клас, който да дефинира общо поведение за цялата йерархия

  3. Всеки отделен наследник дефинира конкретно поведение за него (при нужда)

Йерархия от Класове

Винаги търсим базов клас

public class Entity {
	private String identifier;
	
	public String getIdentifier() {
		return identifier;
	}
	
	public Entity(String identifier) {
		this.identifier = identifier;
	}
}

Наследникът трябва да даде достатъчната информация нагоре.

public class Student extends Entity {
	
	public Student(String identifier) {
		super(identifier);
	}
}

super вика конструкторът на Entity.

public class Student extends Entity {
	
	public Student(String identifier) {
		super(identifier);
	}
}

super е this-а на класа, който сме наследили.

public class Student extends Entity {
	
	public Student(String identifier) {
		super(identifier);
	}
}

Даваме наше поведение

public class Student extends Entity {
	private String name;
	
	public Student(String identifier) {
		super(identifier);
	}
	
	public Student(String identifier, String name) {
		this(identifier);
		this.name = name;
	}
}

Може да направим следното нещо

Entity ent = new Student("1", "Ivo");

Имаме същият ефект както при интерфейсите.

Обобщението изглежда така

public class A extends B implements C, D {
...
}
// Всичко това е възможно
A a = new A();
B a1 = new A();
C a2 = new A();
D a3 = new A()

Обобщението изглежда така

public class E extends A {
...
}
// Всичко това е възможно
E e = new E();
A e1 = new E();
B e2 = new E();
C e3 = new E();
D e4 = new E();

Обобщението изглежда така

Type1 t = new Type2();

  1. Type1 е клас, който се наследява от Type2 или от някой от класовете, които Type2 наследява.

  2. Type1 е интерфейс, който се имплементира от Type2 или от някой от класовете, които Type2 наследява

Обобщението изглежда така

Type1 t = new Type2();

  1. Type1 дава множеството на публичните методи.

  2. Type2 дава тяхната имплементация.

Абстрактни Класове

  1. Не може да вдигаме инстанция от тях.

  2. Могат да дефинират абстрактни методи - методи без имплементация

  3. Ако клас наследни абстрактен клас, то той е задължен да имплементира абстракните методи*

  4. Освен ако и той не стане абстрактен.

public abstract class Runner {
	protected String result;
	protected String code;
	protected String test;
	
	public Runner(String code, String test) {
		this.code = code;
		this.test = test;
	}
	
	public String run() {
		lint();
		compile();
		execute();
		
		return result;
	}
	
	public abstract void lint();
	public abstract void compile();
	public abstract void execute();
}
public class PythonRunner extends Runner {
	public PythonRunner(String code, String test) {
		super(code, test);
	}

	public void lint() {}
	public void compile() {}

	public void execute() {
		result = "OK";
	}
}

Примерен наследник

Method Overriding

  1. Предефинираме метод в наследника.

  2. Ако искаме да използваме super имплементацията, можем да го направим чрез super

  3. Eclipse слага @Override, за да ви помогне визуално кои методи идват по наследство

Method Overriding

public class RealPythonRunner extends PythonRunner {
	public RealPythonRunner(String code, String test) {
		super(code, test);
	}
	@Override
	public void execute() {
		super.execute();
		result = "NOT OK";
	}
}

Method Overriding

  • Често срещан pattern

  • Позволява "hooking" в даден клас

    • викате super()

    • Правите каквото вие искате да направите

QA And Automation - Intro to Java - Part 3

By Hack Bulgaria

QA And Automation - Intro to Java - Part 3

  • 1,601