다음과 같이 타입 매개변수를 사용하여 Boundary 클래스를 상속받은 객체들만 필드로 들어올 수 있게 하였음
public abstract class GuiComponent<T extends Boundary> {
private CustomColor color;
private T renderingBound; // 타입 매개변수를 사용한 필드
private T interactionBound;
public GuiComponent(CustomColor color, T renderingBound) {
this.color = color;
this.renderingBound = renderingBound;
}
public GuiComponent(CustomColor color, T renderingBound, T interactionBound) {
this.color = color;
this.renderingBound = renderingBound;
this.interactionBound = interactionBound;
}
public T getRenderingBound() {
return renderingBound;
}
public T getInteractionBound() {
return interactionBound;
}
public abstract void render(DrawContext context);
public CustomColor getColor() {
return color;
}
}
그리고 상기한 GuiComponent를 상속받는 구현체를 만들고, 다음과 같이 생성자로 Boundary를 상속받은 객체인 RectangularBound 를 받고 있었음
public class TextBox extends GuiComponent {
TextRenderer textRenderer;
private String content;
private float fontScale;
// 생성자에 Boundary의 하위 클래스인 RectangularBound를 매개변수로 지정
public TextBox(CustomColor color, RectangularBound bound, TextRenderer textRenderer, String content, float fontScale) {
super(color, bound);
this.textRenderer = textRenderer;
this.content = content;
this.fontScale = fontScale;
}
@Override
public void render(DrawContext context) {
render(context, textRenderer);
}
private void render(DrawContext context, TextRenderer textRenderer) {
RectangularBound bound = this.getRenderingBound();
int screenWidth = context.getScaledWindowWidth();
int screenHeight = context.getScaledWindowHeight();
List<String> contentLines = splitContent(textRenderer, content, (int)(screenWidth * bound.getWidthRatio()));
GeneralUtil.repeatWithIndex(contentLines.size(), i -> {
RenderingHelper.renderText(Alignment.LEFT, context, fontScale, contentLines.get(i),
bound.getxRatio(), bound.getyRatio() + 0.04 * i ,
0xffffff);
});
}
private List<String> splitContent(TextRenderer textRenderer, String content, int boundWidth){
List<String> result = new ArrayList<>();
String line = "";
int i = 0;
while (i < content.length()) {
line = "";
while (i < content.length() && textRenderer.getWidth(line + content.charAt(i)) <= boundWidth) {
line += content.charAt(i);
i++;
}
result.add(line);
}
return result;
}
}
문제는 여기서 발생함. 생성자를 통해 전달 받은 RectangularBound가 Boundary로 업캐스팅 되어, 고유한 필드와 메서드에 접근이 불가능해지는 현상이 확인되었음
원인은 TextBox 클래스를 선언하면서 부모 클래스가 가진 타입 매개변수에 대한 정보를 명시하지 않았기 때문에 제네릭 타입 소거에 의해 T가 Boundary로 대체되었기 때문. 타입 소거에 대해 좀 더 자세히 알아보려 했으나 현재로서는 깊은 이해가 불가능
다음과 같이 하위 클래스를 선언하면서 타입 매개변수에 대한 정보를 같이 명시하였음
public class TextBox extends GuiComponent<RectangularBound>
타입 매개변수 T에 RectangularBound 타입을 전달하였기 때문에 더 이상 타입 소거가 일어나지 않으며, 필드가 Boundary로 업캐스팅되지 않음