返回子类的Object的通用getter

时间:2017-08-17 14:12:39

标签: java generics inheritance

我们假设我有3个班级:CarConvertibleGarage

CarConvertible继承自的抽象类:

Convertible有一个名为unfoldRoof()的特定方法。

Garage包含一个Car,其中包含以下getCar()方法:

public Car getCar() {
    return car;
}

通过getter访问Car属性时,我无法使用特定的Convertible方法unfoldRoof()

如何构建一个泛型 getter,它返回子类而不是抽象父类

4 个答案:

答案 0 :(得分:1)

通用界面中的特定于运行时的类型

您可以指定一般的扩展返回类型

public abstract Car <CarType extends Car>{
  public abstract CarType getTypedCar();
}

......然后......

public class Convertable extends Car<Convertable> {
  public <Convertable> getTypedCar(){
    return this;
  }
}

但是当你做getTypedCar()时,你仍然需要知道你得到了什么类型。

Convertable convertable = car.getTypedCar();

并且它会是相同的(就运行时类型的安全性而言)并不是因为它没有产生并且写作

 Convertable convertable = (Convertable)car;

容器保存接口实例的运行时特定类型

如果您希望Garage知道其持有的Car的运行时类型,则会出现此问题。您希望它保留任何Car但您希望它在运行时返回特定类型,它在编译时不知道所以只能定义为返回特定于它的对象持有;在这种情况下,Car。 你可以通过让Garage只保持Convertables像@Valentin Ruano建议来解决这个问题,但在现实生活中,这是一个愚蠢的想法,因为你的对象不能代表现实世界的对象他们应该这样做。也就是说你可以建造一个只需要敞篷车的车库吗?!

您的需求

这完全取决于您的需求。例如,您是否需要知道汽车从Garage中删除它的类型?或者您可以返回Car然后使用上面的解决方案来getTypedCar()吗?同样,您需要知道(假设)要执行此操作的汽车类型,但为了灵活,需要在此设计中进行此操作。

这个假设的另一个地方是Garage的吸气剂,你可以有一个方法getCar(Class carType)并且如果所需的车型不是&#39则让它抛出NoSuchCarException ; t,否则返回carType的类型。

答案 1 :(得分:1)

这是一项功能,因此请使用可选:

public virtual void Delete(Expression<Func<T,bool>> predicate)
{
   var query = Context.Set<T>().Where(predicate);
   Context.Set<T>().RemoveRange(query);
}

顺便说一下。一般中的继承Car / Convertible 不是真的需要,你可以有像

这样的接口
class Car {
    <C extends Car> Optional<C> as(Class<C> type) {
        return type.isInstance(this)
                ? Optional.of(type.cast(this))
                : Optional.empty();
    }
}

Car car = new Convertible();

car.as(Convertible.class).ifPresent(convertible -> {
    convertible.unfoldRoof();
});

但是,这需要在地图字段等中安装功能/功能。

答案 2 :(得分:0)

你可以为刚刚返回的汽车定义unfoldRoof(),什么都不做。

答案 3 :(得分:0)

最优雅的解决方案是使abstract class Car { String make(); int year(); //... } class Convertible extends Car { void unfoldRoof() { /* whatever */ } } class Garage<C extends Car> { private C car = null; public Garage() {} public boolean isEmpty() { return car == null; } public C getCar() { return car; } public void park(final C car) { if (!isEmpty()) { throw new IllegalStateException("Garage is full!!"); } else { this.car = car; } } public C exit() { if (isEmpty()) { throw new IllegalArgumentException("There is no cars in garage"); } else { final C exitingCar = car; car = null; return exitingCar; } } } class Main { public static void main(String[] args) { final Garage<Convertible> myGarage = new Garage(); final Convertible car = ...; myGarage.park(car); //... car = myGarage.getCar(); car.unfoldRoof(); } } 通用:

import json
import webbrowser
from hashlib import md5
import urllib3

class PyLast():

def __init__(self, API_KEY, SECRET, SESSION_KEY=None):
    self.__API_KEY__ = API_KEY
    self.__SECRET__ = SECRET
    self.__SESSION_KEY__ = SESSION_KEY
    self.__api_signature__ = None
    if SESSION_KEY is None:
        self.__is_authorized__ = False
    else:
        self.__is_authorized__ = True

    self.__http__ = urllib3.PoolManager()

def request_token(self):
    print("Getting the token...")
    url = 'http://ws.audioscrobbler.com/2.0/?method=auth.gettoken&api_key={}&format=json'.format(self.__API_KEY__)
    req_response = self.__http__.request('GET', url, headers={'User-Agent' : 'Mozilla/5.0'})
    if req_response.status == 200:
        json_data = json.loads(req_response.data.decode('utf-8'))
        TOKEN = json_data['token']
        self.__TOKEN__ = TOKEN
        return TOKEN
    else:
        print("Error with code " + req_response.status)

def authorize(self):
    if not self.__is_authorized__:
        url = 'http://www.last.fm/api/auth/?api_key={}&token={}'.format(self.__API_KEY__, self.__TOKEN__)
        # open browser to authorize app
        webbrowser.open(url, new=0, autoraise=True)
        # Make sure authorized
        self.__is_authorized__ = True


def start_session(self):
    if self.__is_authorized__:
        data = "api_key{}methodauth.getSessiontoken{}{}" \
                                     .format(self.__API_KEY__, self.__TOKEN__, self.__SECRET__).encode(
            encoding='utf-8')
        self.__api_signature__ = md5(data).hexdigest()
        url = 'http://ws.audioscrobbler.com/2.0/?method=auth.getSession&api_key={}&token={}&api_sig={}&format=json'.format(
            self.__API_KEY__, self.__TOKEN__, self.__api_signature__)
        req_response = self.__http__.request('GET', url)

        if req_response.status == 200:
            json_data = json.loads(req_response.data.decode('utf-8'))
            session_key = json_data['session']['key']
            self.__SESSION_KEY__ = session_key

            url = 'http://ws.audioscrobbler.com/2.0/?method=track.love&api_key={}&api_sig={}&sk={}&artist=cher&track=believe&format=json'.format(
                self.__API_KEY__, self.__api_signature__, self.__SESSION_KEY__)
            req_response = self.__http__.request('POST', url)

            return self.__SESSION_KEY__
        else:
            print("Error with code " + str(req_response.status))




    else:
        print("Not authorized!")