Home CPSC 330

Wrap Up

Reflection

Reflection is an advanced feature in Java which allows us to examine and work with objects and methods at runtime.

For example, we can write a program that creates an object, and calls a method on it, without having to hard code the class name or method name:


import java.lang.reflect.*;

// a simple class
class Thing {
  public void print() {
    System.out.println("Hello!");
  }
}


public class Simple {
  public static void main(String args[]) {
    Object a = null;
    try {
      // get the class by name
      a = Class.forName("Thing").newInstance();
    }
    // it might not exist!
    catch(ClassNotFoundException e) {
      System.out.println("Class not found!");
    }
    // we might not be able to create it (ie if it's abstract or is an interface)
    catch(InstantiationException e) {
      System.out.println("Class could not be created!");
    }
    // we might not be allowed to create it (ie if the constructor is private)
    catch(IllegalAccessException e) {
      System.out.println("Class could not be created!");
    }

    // get the method by name
    Method m = null;
    try {
      m = a.getClass().getDeclaredMethod("print", new Class[0]);
    }
    // it might not exist!
    catch(NoSuchMethodException e) {
      System.out.println("Method not found!!");
    }

    // call the method we got on the object a
    try {
      m.invoke(a);
    }
    // it might not be public!
    catch(IllegalAccessException e) {
      System.out.println("Can't access method!");
    }
    // the method itself might throw an exception when it's run!
    catch(InvocationTargetException e) {
      System.out.println("The method we called threw an exception!");

    }
  }
}

There are many exceptions that can occur when doing this - these are things that the compiler normally checks. The benefit of reflection is that we have more flexibility. We can load the class and/or method names to create from a file, or some other place, and change them without recompiling the program.

We can also write code that looks through classes at run-time. For example, this program prints all of the methods a class input from the user.


import java.util.*;
import java.lang.reflect.*;

public class MethodList {
  public static void main(String args[]) {
    // get class name
    Scanner in = new Scanner(System.in);
    System.out.println("Enter class (with full package name) to list methods of:");
    String name = in.next();

    try {
      // get the class
      Class c = Class.forName(name);

      // get the methods
      Method [] methods = c.getMethods();

      // loop through each one
      for(Method m : methods) {
        // print the method out as a string
        System.out.println(m.toString());
      }
    } catch(ClassNotFoundException e) {
      System.out.println("Class '" + name + "' was not found!");
    }
  }
}

Reflection is also for programs that need to interpret Java code such as IDEs, debuggers, testing frameworks, documentation generators etc.


OOP in C++

Java's object-oriented features were inspired by those of C++, but there are many differences. The biggest is that, by default, polymorphism does not work in C++. Consider the following program:

#include 
using namespace std;

class Base {
  public:
    void print() {
      cout << "Base class!\n";
    }
};

class Derived : public Base {
  public:
    void print() {
    cout << "Derived!\n";
  }
};

int main() {
  Base* object = new Derived();
  object->print();
  return 0;
}

This program does not work as expected because C++ uses static method binding by default. To use dynamic binding, we need to specify the function is "virtual":


#include <iostream>
using namespace std;

class Base {
  public:
    virtual void print() {
      cout << "Base class!\n";
    }
};

class Derived : public Base {
  public:
    virtual void print() {
    cout << "Derived!\n";
  }
};

int main() {
  Base* object = new Derived();
  object->print();
  return 0;
}

It's only necessary to specify virtual in the Base class, but doesn't hurt to repeat it.

If we wanted to make a base class function abstract, that can be done with the following syntax:


#include <iostream>
using namespace std;

class Base {
  public:
    virtual void print() = 0;
};

class Derived : public Base {
  public:
    virtual void print() {
    cout << "Derived!\n";
  }
};

int main() {
  Base* object = new Derived();
  object->print();
  return 0;
}
This is called a "pure" virtual function in C++ terms.

Multiple Inheritance

C++ does not have Java's interfaces. Instead, C++ allows inheriting from as many classes as you want.

This can cause problems in some instances.

One is that we can have multiple variables or functions with the same name:


class A { 
  public:
    A() { 
      x = 1;
    }   
    int x;
};

class B { 
  public:
    B() { 
      x = 2;
    }   
    int x;
};

class C : public A, public B { 

};

This is handled by the compiler requiring us to specify which one is meant:


int main() { 
  C c;
  cout << c.A::x << endl;
  return 0;
}

A worse problem is the "diamond problem" or the "deadly diamond of death" problem which is illustrated below:

Here D inherits from B and C where each of those have inherited from A. The issue with this is whether D will have one or two copies of A's data.

The way inheritance typically works will give us two copies!


class A { 
  public:
    void f() {cout << "A";}
};

class B : public A { 
};

class C : public A { 
};

class D : public B, public C { 
};                                                                                                                   


int main() { 
  D d;
  d.f();
  return 0;
}

x.cpp: In function 'int main()':
x.cpp:21:5: error: request for member 'f' is ambiguous
x.cpp:6:10: error: candidates are: void A::f()
x.cpp:6:10: error:                 void A::f()

The compiler doesn't know if we want A::f or A::f.

We can work around this by marking the inheritance as "virtual" on one of the paths.


OOP Summary

Object-oriented programming has become the dominant way of developing programs. Benefits include: OOP also has detractors. Criticisms of OOP include: Either way, you need to be comfortable with it to program with others.

Copyright © 2018 Ian Finlayson | Licensed under a Creative Commons Attribution 4.0 International License.