我班上有以下成员:
List<? extends SomeObject> list;
当我尝试做时:
list.add(list.get(0));
我得到:
Test.java:7: error: no suitable method found for add(CAP#1)
list.add(list.get(0));
^
method Collection.add(CAP#2) is not applicable
(argument mismatch; Object cannot be converted to CAP#2)
method List.add(CAP#2) is not applicable
(argument mismatch; Object cannot be converted to CAP#2)
where CAP#1,CAP#2 are fresh type-variables:
CAP#1 extends Object from capture of ? extends Object
CAP#2 extends Object from capture of ? extends Object
我的问题是双重的:
为什么不编译?为什么我不能将get()
的结果传递给add()
?
又如何在不借助强制转换的情况下以其他方式实现这一目标?
我了解在使用<T extends SomeObject>
的方法中,我不能只是说:
T someObject = list.get(0);
list.add(someObject);
因为我的T可能是?
扩展名之外的另一个扩展名。
我也明白我不能说:
List<? extends SomeObject> list1;
List<? extends SomeObject> list2;
list1.add(list2.get(0));
但是由于add和get应该在list.add(list.get(0))
中使用相同的泛型类型,所以我不明白为什么编译器不接受它。
我真正需要的是
[something of type T where T is whatever was used to instantiate list] someObject = list.get(0);
list.add(someObject);
以便我以后可以
list.add(someObject);
我认为我不必为整个课程模板化,是吗?
class MyClass<T extends SomeObject> {
List<T> list;
,然后再使用
T someObject = list.get(0);
当然可以,但是要拧紧我代码的其他部分。
所以第一个问题是为什么不起作用,第二个问题是最佳的解决方法是什么?
答案 0 :(得分:3)
我的问题有两个,为什么我不能:
// Utility function to get the price of a variation from it's attribute value function get_the_variation_price_html( $product, $name, $term_slug ){ foreach ( $product->get_available_variations() as $variation ){ if($variation['attributes'][$name] == $term_slug ){ return strip_tags( $variation['price_html'] ); }`enter code here` } } // Add the price to the dropdown options items. add_filter( 'woocommerce_dropdown_variation_attribute_options_html', 'show_price_in_attribute_dropdown', 10, 2); function show_price_in_attribute_dropdown( $html, $args ) { // Only if there is a unique variation attribute (one dropdown) if( sizeof($args['product']->get_variation_attributes()) == 1 ) : $options = $args['options']; $product = $args['product']; $attribute = $args['attribute']; $name = $args['name'] ? $args['name'] : 'attribute_' . sanitize_title( $attribute ); $id = $args['id'] ? $args['id'] : sanitize_title( $attribute ); $class = $args['class']; $show_option_none = $args['show_option_none'] ? true : false; $show_option_none_text = $args['show_option_none'] ? $args['show_option_none'] : __( 'Choose an option', 'woocommerce' ); if ( empty( $options ) && ! empty( $product ) && ! empty( $attribute ) ) { $attributes = $product->get_variation_attributes(); $options = $attributes[ $attribute ]; } $html = '<select id="' . esc_attr( $id ) . '" class="' . esc_attr( $class ) . '" name="' . esc_attr( $name ) . '" data-attribute_name="attribute_' . esc_attr( sanitize_title( $attribute ) ) . '" data-show_option_none="' . ( $show_option_none ? 'yes' : 'no' ) . '">'; $html .= '<option value="">' . esc_html( $show_option_none_text ) . '</option>'; if ( ! empty( $options ) ) { if ( $product && taxonomy_exists( $attribute ) ) { $terms = wc_get_product_terms( $product->get_id(), $attribute, array( 'fields' => 'all' ) ); foreach ( $terms as $term ) { if ( in_array( $term->slug, $options ) ) { // Get and inserting the price $price_html = get_the_variation_price_html( $product, $name, $term->slug ); $html .= '<option value="' . esc_attr( $term->slug ) . '" ' . selected( sanitize_title( $args['selected'] ), $term->slug, false ) . '>' . esc_html( apply_filters( 'woocommerce_variation_option_name', $term->name ) . ' ::: ' . $price_html ) . '</option>'; } } } else { foreach ( $options as $option ) { $selected = sanitize_title( $args['selected'] ) === $args['selected'] ? selected( $args['selected'], sanitize_title( $option ), false ) : selected( $args['selected'], $option, false ); // Get and inserting the price $price_html = get_the_variation_price_html( $product, $name, $term->slug ); $html .= '<option value="' . esc_attr( $option ) . '" ' . $selected . '>' . esc_html( apply_filters( 'woocommerce_variation_option_name', $option ) . ' ::: ' . $price_html ) . '</option>'; } } } $html .= '</select>'; endif; return $html; }
因为编译器不够聪明,无法知道您是将list.add(list.get(0));
中的内容添加回list
中。评估后,编译器不认为list
与list.get(0)
有任何关系:它只是类型为list
的“某些表达式”。
要解决此问题,请添加具有自己的类型变量的方法:
? extends SomeObject
,并用以下内容替换原始的private <T> void addFirst(List<T> list) {
list.add(list.get(0));
}
:
list.add(list.get(0));
这仅在方法上定义类型变量,并且不需要在类外部可见,因此您不需要类级类型变量。
也许值得指出的是,这类似于Collections.swap
method:使用的是addFirst(list);
而不是set
,但是从泛型的角度来看,这是同一件事:>
add
这采用了技术上类型安全的方法,并且确实避免了强制类型转换;但这有点麻烦,因为它使用原始类型。
我想这仅仅是出于向后兼容的原因。只要有机会再次编写它,就可以像上面的@SuppressWarnings({"rawtypes", "unchecked"})
public static void swap(List<?> list, int i, int j) {
// instead of using a raw type here, it's possible to capture
// the wildcard but it will require a call to a supplementary
// private method
final List l = list;
l.set(i, l.set(j, l.get(i)));
}
方法中那样定义类型变量。
答案 1 :(得分:0)
当使用通配符时,我们应该遵循Java泛型和集合中介绍的The Get and Put Principle
:
Get 和 Put 原则:当你只从一个
结构,当您只将值放入结构时使用 extends
通配符,并且不要使用
获取和放置时的通配符。
在您的情况下,不要使用通配符,因为您既从列表中获取元素,又将元素放入列表。