So I have parent and child class. I want them to output some field’s value (if it exists), and there’s a problem.
open class Parent { // there can be 'name' field with some value // if 'name' field exists, try block will be executed otherwise catch override fun toString(): String { return try { val name = this.javaClass.getDeclaredField("name").get(this) "name exists: $name" } catch (e: Exception) { "name does not exist" } } } open class Child : Parent() { open val name = "child!" } fun main() { val parent = Parent() println(parent) val child = Child() println(child) }
Child class has field ‘name’, but the result has two strings “name does not exist”. Also if there’s name in Parent class, the second string will anyway be “name does not exist”.
I managed to catch the error: IllegalAccessException – parent class cannot access child field despite child is open, and the ‘name’ field too. It also tells that Child’s member is final and private.
What am I doing wrong? I want every class to output value of field name (if it exist). Maybe I should explicitly write toString() function for every class?
Advertisement
Answer
Wouldn’t it be better to declare name
in the parent class, have it null
by default, and allow the child class to set it? That way you can null check the field to see if it “exists” or not.
open class Parent { open val name: String? = null override fun toString(): String = name ?: "name does not exist" } open class Child : Parent() { override val name = "child!" }
Right now you’re using reflection (which is usually a warning sign), and your superclass has knowledge about the implementation details of its subclass (it might have a field called name
). If the parent should be aware of that field, why not explicitly make it part of the inheritance system, instead of working around it with reflection? It’s extremely brittle, and unless you have good reason for messing around with this stuff, it’s probably better to just work within the language (and its limitations)