java List的<>中 方法参数是父类对象的list。传入子类对象时的处理

本文通过具体的Java代码示例,介绍了如何在父类与子类间使用继承特性,并展示了如何利用泛型来处理不同类型的对象列表。通过getA方法处理父类对象,演示了在实际编程中继承和泛型的具体运用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

父类:
public class FatherA {

    private String a;

 
    public String getA() {
        return a;
    }

    public void setA(String a) {
        this.a = a;
    }

}

子类:

public class Children extends FatherA {

    private String b;

    public String getB() {
        return b;
    }

    public void setB(String b) {
        this.b = b;
    }
    
}

Test:getA用来处理父类的对象

public class Test {
    public static void main(String[] args) {
        Children cl = new Children();
        cl.setB("1");
        cl.setA("2");
        getA(cl);
        System.out.println(cl.getA());
    }

    private static void getA(FatherA f) {
        f.setA("3");
    }
}


Test:getA方法用来处理父类对象的list。

ArrayList<FatherA>和ArrayList<Children>是两个不同的泛型

public class Test {
    public static void main(String[] args) {
        Children cl = new Children();
        cl.setB("1");
        cl.setA("2");
        List<Children> list = new ArrayList<Children>();
        list.add(cl);
        getA(list);
        System.out.println(cl.getA());
    }

    private static <T extends FatherA> void getA(List<T> list) {
        for (int i = 0; i < list.size(); i++) {
            list.get(i).setA("3");
        }
    }
}




<think>在C#中,`List<Man>` 或 `List<Woman>` 不能直接赋值给 `List<People>`,即使 `Man` 和 `Woman` 是 `People` 的子类。这是因为泛型类型参数在C#中默认是不支持协变的(对于`List<T>`这样的集合类型)。也就是说,`List<Man>` 并不是 `List<People>` 的子类型,尽管 `Man` 是 `People` 的子类。 ### 原因: C#的泛型类型在默认情况下是“不变”的。这意味着,即使两个类型有继承关系,它们的泛型类型(如`List<T>`)之间也没有继承关系。因此,不能直接将`List<Man>`赋值给`List<People>`。因为如果允许这样做,那么就可以通过`List<People>`向集合中添加一个`Woman`对象(因为`Woman`也是`People`),但实际集合是`List<Man>`,这会导致类型不安全。 ### 解决方法: 有几种方法可以解决这个问题: 1. **使用协变接口**: 如果使用的是C# 4.0或更高版本,可以使用支持协变的接口,例如`IEnumerable<out T>`。因为`IEnumerable<T>`接口被声明为协变(通过`out`关键字),所以可以将`IEnumerable<Man>`赋值给`IEnumerable<People>`。 例如,将返回类型改为`IEnumerable<People>`: ```csharp public IEnumerable<People> GetPeople() { List<Man> men = new List<Man>(); // 添加一些Man对象 return men; // 因为IEnumerable<out T>是协变的,所以可以这样返回 } ``` 2. **使用`List<T>`的`ConvertAll`方法**: 如果你需要返回一个`List<People>`,那么你可以将`List<Man>`转换为`List<People>`,通过显式转换每个元素: ```csharp public List<People> GetPeople() { List<Man> men = new List<Man>(); // 添加一些Man对象 return men.ConvertAll<People>(x => x); // 因为每个Man都是People,所以可以转换 } ``` 3. **使用`Cast<T>`方法(LINQ)**: 使用LINQ的`Cast`方法将`List<Man>`转换为`List<People>`: ```csharp public List<People> GetPeople() { List<Man> men = new List<Man>(); // 添加一些Man对象 return men.Cast<People>().ToList(); } ``` 4. **使用`Select`方法(LINQ)**: 同样使用LINQ,通过`Select`方法进行转换: ```csharp public List<People> GetPeople() { List<Man> men = new List<Man>(); // 添加一些Man对象 return men.Select(x => (People)x).ToList(); } ``` 5. **创建新的`List<People>`并添加元素**: 最直接的方法,创建一个新的`List<People>`,然后将`List<Man>`中的所有元素添加进去: ```csharp public List<People> GetPeople() { List<Man> men = new List<Man>(); // 添加一些Man对象 List<People> people = new List<People>(); people.AddRange(men); return people; } ``` ### 注意: - 如果使用协变接口(如`IEnumerable<People>`),那么你只能提供只读访问,因为协变只支持输出(只读)。如果你需要修改集合(如添加或删除元素),则不能使用协变接口。 - 如果方法需要返回`List<People>`并且允许修改,那么上述方法2-5都是可行的,但会创建一个新的列表(即原列表的浅拷贝)。如果原列表很大,可能会有性能开销。 ### 示例代码: 假设有类定义如下: ```csharp public class People { } public class Man : People { } public class Woman : People { } ``` 方法实现: ```csharp // 方法1:使用协变接口IEnumerable<People> public IEnumerable<People> GetPeopleAsEnumerable() { List<Man> men = new List<Man> { new Man(), new Man() }; return men; // 协变允许 } // 方法2:使用ConvertAll public List<People> GetPeopleList() { List<Man> men = new List<Man> { new Man(), new Man() }; return men.ConvertAll<People>(x => x); } // 方法3:使用Cast public List<People> GetPeopleListWithCast() { List<Man> men = new List<Man> { new Man(), new Man() }; return men.Cast<People>().ToList(); } // 方法4:使用Select public List<People> GetPeopleListWithSelect() { List<Man> men = new List<Man> { new Man(), new Man() }; return men.Select(x => (People)x).ToList(); } // 方法5:使用AddRange public List<People> GetPeopleListWithAddRange() { List<Man> men = new List<Man> { new Man(), new Man() }; List<People> people = new List<People>(); people.AddRange(men); return people; } ``` ### 相关问题: §§相关问题§§: 1. 什么是C#中的泛型协变和逆变? 2. 为什么`List<Derived>`不能直接赋值给`List<Base>`? 3. 在C#中,哪些泛型接口支持协变或逆变? 4. 如何设计一个支持协变的泛型接口?</think>### 问题原因 在 C# 中,`List<Man>` 或 `List<Woman>` 不能直接赋值给 `List<People>`,即使 `Man` 和 `Woman` 继承自 `People`。这是因为泛型的 **不变性(Invariance)**: - `List<T>` 是**不变**的泛型类型,即使 `Man` 是 `People` 的子类,`List<Man>` 也不是 `List<People>` 的子类。 - 直接赋值会导致类型安全问题:如果允许 `List<Man> men = new List<People>()`,就可能向集合中添加非 `Man` 类型的对象(如 `Woman`),破坏类型约束。 ### 解决方法 以下是 5 种安全转换的方式: #### 1. 使用协变接口 `IEnumerable<out T>` ```csharp public IEnumerable<People> GetPeople() { List<Man> men = new List<Man> { new Man(), new Man() }; return men; // 协变支持子类集合转父类集合 } ``` **解释**: `IEnumerable<out T>` 的 `out` 关键字支持协变,允许将 `IEnumerable<Man>` 视为 `IEnumerable<People>`。但此接口是只读的。 --- #### 2. 使用 `List.ConvertAll` 方法 ```csharp public List<People> GetPeople() { List<Man> men = new List<Man> { new Man(), new Man() }; return men.ConvertAll<People>(man => man); // 显式转换每个元素 } ``` **解释**: 通过 lambda 表达式将每个 `Man` 显式转换为 `People`,生成新的 `List<People>`。 --- #### 3. 使用 LINQ 的 `Cast<T>()` ```csharp public List<People> GetPeople() { List<Man> men = new List<Man> { new Man(), new Man() }; return men.Cast<People>().ToList(); // 强制类型转换 } ``` **解释**: `Cast<People>()` 将集合中的每个元素转换为 `People` 类型,生成新列表。 --- #### 4. 使用 LINQ 的 `Select` + `ToList` ```csharp public List<People> GetPeople() { List<Man> men = new List<Man> { new Man(), new Man() }; return men.Select(man => (People)man).ToList(); // 显式转换 } ``` **解释**: 通过 `Select` 将每个元素显式转型为 `People`,再通过 `ToList()` 生成新集合。 --- #### 5. 创建新集合并用 `AddRange` ```csharp public List<People> GetPeople() { List<Man> men = new List<Man> { new Man(), new Man() }; List<People> people = new List<People>(); people.AddRange(men); // 添加子类集合到父类集合 return people; } ``` **解释**: `AddRange` 接受 `IEnumerable<T>`,由于协变支持,允许传入 `IEnumerable<Man>`。 --- ### 类定义参考 ```csharp public class People { } public class Man : People { } public class Woman : People { } ``` ### 关键概念总结 - **协变(Covariance)**:允许使用比原始类型更泛化的类型(子类父类),通过 `out` 关键字实现(如 `IEnumerable<out T>`)。 - **不变性(Invariance)**:泛型类型参数必须完全匹配(`List<T>` 不支持子类父类转换)。 - **类型安全**:防止将错误类型添加到集合中。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值