我在Java中有以下复杂的类型层次结构:
Build.VERSION.SDK_INT < Build.VERSION_CODES.M
我有一些处理player.setDataSource(this, mediaUri)
s的静态方法:
// the first type
interface Element<Type extends Element<Type>> {
Type foo(Type a, Type b);
}
// the second type
interface Payload<Type extends Payload<Type>> {
Type bar(Type[] array);
}
// some toy implementation
final class SomePayload implements Payload<SomePayload> {
@Override
public SomePayload bar(SomePayload[] array) { return array[0]; }
}
// mix of first and second interfaces
interface ComplicatedElement<
PayloadT extends Payload<PayloadT>,
ObjectT extends ComplicatedElement<PayloadT, ObjectT>>
extends Element<ObjectT> {
PayloadT getPayload();
ObjectT add(ObjectT a, ObjectT b);
}
// some toy implementation
final class SomeComplicatedElement
implements ComplicatedElement<SomePayload, SomeComplicatedElement> {
final SomePayload data;
public SomeComplicatedElement(SomePayload data) {
this.data = data;
}
@Override
public SomePayload getPayload(){ return data; }
@Override
public SomeComplicatedElement foo(SomeComplicatedElement a, SomeComplicatedElement b) {
return b;
}
@Override
public SomeComplicatedElement add(SomeComplicatedElement a, SomeComplicatedElement b) {
return a;
}
}
现在,从Java我可以调用ComplicatedElement
而不会出现这样的问题:
public static <PayloadT extends Payload<PayloadT>,
ObjectT extends ComplicatedElement<PayloadT, ObjectT>>
List<ObjectT> method(ObjectT input) {
return Collections.singletonList(input);
}
然而,当我尝试在Scala中做同样的事情时:
method
我有这个编译错误:
public static void main(String[] args) {
System.out.println(method(new SomeComplicatedElement(new SomePayload())));
}
我可以通过明确指定类型参数来解决这个问题:
import FooBarJava.{SomeComplicatedElement, SomePayload, method}
def main(args: Array[String]): Unit = {
println(method(new SomeComplicatedElement(new SomePayload())))
}
但它非常烦人,我想避免这种情况(我想这可能是因为Java编译器可以正常工作)。有没有办法这样做?
答案 0 :(得分:3)
(我想这可能是因为Java编译器可以正常工作)
Scala具有比Java更丰富的类型系统。例如,在Java中,Scala中没有类似于Nothing
的类型(即通用子类型)。因此,有时类型系统语言中的编译器无法推断类型,而类似情况下,使用较差类型系统的语言编译器可能会这样做。
如果指定类型参数太烦人,为什么不创建一些辅助方法?
private def methodWithPayload(data: SomePayload): java.util.List[SomeComplicatedElement] =
method[SomePayload, SomeComplicatedElement](new SomeComplicatedElement(data))
methodWithPayload(new SomePayload)
在Java中,唯一的选项是<SomePayload, SomeComplicatedElement>method(..)
,在Scala中有两个选项method[SomePayload, SomeComplicatedElement](..)
和method[Nothing, SomeComplicatedElement](..)
,两个选项都有效。
答案 1 :(得分:0)
我提出的一个丑陋的黑客(在使用第三方Java库时特别有用)是在Scala项目中创建一个单独的Java文件,它会使所有必需的不安全类型擦除:
import FooBarJava.{SomeComplicatedElement, SomePayload}
import HackScala.method
def main(args: Array[String]): Unit = {
// this will work fine and return correct type
println(method(new SomeComplicatedElement(new SomePayload())))
}
然后所有人都可以在Scala中正常工作:
public class ObservableDictonary<TKey, TValue> : Dictionary<TKey, TValue>, INotifyCollectionChanged, INotifyPropertyChanged
{
public event NotifyCollectionChangedEventHandler CollectionChanged;
public event PropertyChangedEventHandler PropertyChanged;
public new void Add(TKey key, TValue value)
{
base.Add(key, value);
if (!TryGetValue(key, out _)) return;
var index = Keys.Count;
OnPropertyChanged(nameof(Count));
OnPropertyChanged(nameof(Values));
OnCollectionChanged(NotifyCollectionChangedAction.Add, value, index);
}
public new void Remove(TKey key)
{
if (!TryGetValue(key, out var value)) return;
var index = IndexOf(Keys, key);
OnPropertyChanged(nameof(Count));
OnPropertyChanged(nameof(Values));
OnCollectionChanged(NotifyCollectionChangedAction.Remove, value, index);
base.Remove(key);
}
public new void Clear()
{
}
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
PropertyChanged?.Invoke(this, e);
}
protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
CollectionChanged?.Invoke(this, e);
}
private void OnPropertyChanged(string propertyName)
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
private void OnCollectionChanged(NotifyCollectionChangedAction action, object item)
{
OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item));
}
private void OnCollectionChanged(NotifyCollectionChangedAction action, object item, int index)
{
OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item, index));
}
private int IndexOf(KeyCollection keys, TKey key)
{
var index = 0;
foreach (var k in keys)
{
if (Equals(k, key))
return index;
index++;
}
return -1;
}
}