精华内容
下载资源
问答
  • 假如我们有一个User对象对象字段如下: @Data @Builder class User{ private String name; private int id; } 如果我们存在这样的一个List列表,如果我们希望找出这个List中name为ONE的对象,当然我们可以...

    假如我们有一个User对象,对象字段如下:

    @Data
    @Builder
    class User{
        private String name;
    
        private int id;
    }
    
    

    如果我们存在这样的一个List列表,如果我们希望找出这个List中name为ONE的对象,当然我们可以通过for循环来逐个匹配,然后再放入到另外一个List中,这里我们来展示一种Java1.8中为我们提供的更加简单快捷的方式来实现这样的需求,希望可以对你又帮助,实现方式如下:

    public static void main(String[] args) {
        List<User> userList = new ArrayList<>();
    
        User user1 = User.builder().id(1).name("ONE").build();
        User user2 = User.builder().id(2).name("ZERO").build();
        User user3 = User.builder().id(3).name("TWO").build();
        User user4 = User.builder().id(4).name("FOUR").build();
        User user5 = User.builder().id(5).name("ONE").build();
    
        userList.add(user1);
        userList.add(user2);
        userList.add(user3);
        userList.add(user4);
        userList.add(user5);
        System.out.println("筛选前:" + userList);
        userList = userList.stream().filter(o -> o.getName().equals("ONE")).collect(Collectors.toList());
        System.out.println("筛选后:" + userList);
    }
    
    
    展开全文
  • 文章目录四个线程安全策略可变对象定义可变对象需要满足的条件如何创建可变对象使用final关键字定义可变对象修饰变量示例final 修饰基本数据类型及String: 初始化之后能修改 (线程安全)final修饰引用...


    在这里插入图片描述

    脑图

    在这里插入图片描述


    四个线程安全策略

    在这里插入图片描述

    线程限制

    一个被线程限制的对象,由线程独占,并且只能被占有它的线程修改

    共享只读

    一个共享只读的对象,在没有额外同步的情况下,可以被多个线程并发访问,但是任何线程都不能修改它

    线程安全对象

    一个线程安全的对象或者容器,在内部通过同步机制来保证线程安全,所以其他线程无需额外的同步就可以通过公共接口随意访问它

    被守护对象

    被守护对象只能通过获取特定的锁来访问


    不可变对象定义

    在Java中,有一种对象发布了就是安全的,被称之为不可变对象。

    不可变对象可以在多线程中可以保证线程安全


    不可变对象需要满足的条件

    • 对象创建以后其状态就不能修改
    • 对象所有域都是final类型
    • 对象是正确创建的(在对象创建期间,this引用没有逸出)

    在这里插入图片描述


    如何创建不可变对象

    在这里插入图片描述

    • 类声明成final类型,使其不可以被继承

    • 所有的成员设置成私有的,使其他的类和对象不能直接访问这些成员

    • 对变量不提供set方法

    • 所有可变的成员声明为final,这样只能对他们赋值一次

    • 通过构造器初始化所有成员,进行深度拷贝

    • get方法中,不直接返回对象本身,而是克隆对象,返回对象的拷贝

    提到不可变的对象就不得不说一下final关键字,该关键字可以修饰类、方法、变量:


    使用final关键字定义不可变对象

    final关键字可以修饰类、方法、变量

    在这里插入图片描述

    • 修饰类:不能被继承(final类中的所有方法都会被隐式的声明为final方法)
    • 修饰方法:

    1、锁定方法不被继承类修改;
    2、可提升效率(private方法被隐式修饰为final方法)

    • 修饰变量:

    基本数据类型变量: 初始化之后不能修改
    引用类型变量: 初始化之后不能再修改其引用

    • 修饰方法参数:同修饰变量

    修饰变量示例

    final修饰基本数据类型及String: 初始化之后不能修改 (线程安全)

    在这里插入图片描述

    可知:编译报错,被final修饰后,基本类型和String的变量无法被修改


    final修饰引用类型变量:初始化之后不能再修改其引用,但可以修改值 (线程不安全)

    package com.artisan.example.immutable;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    
    import com.google.common.collect.Maps;
    
    import lombok.extern.slf4j.Slf4j;
    
    @Slf4j
    public class FinalDemo {
    
    	// 基本数据类型 int 使用final修饰 验证被final修饰的基本数据类型无法改变
    	private final static int num = 1;
    
    	// String类型 使用final修饰 验证被final修饰的基本数据类型无法改变
    	private final static String name = "小工匠";
    
    	// 引用类型 初始化之后不能再修改其引用,但是可修改其中值
    	private final static Map<String, Object> map = Maps.newHashMap();
    
    	static {
    		map.put("name", "artisan");
    		map.put("age", 20);
    		map.put("sex", "男");
    	}
    
    	public static void main(String[] args) {
    
    		// 被final修饰的基本数据类型和String无法改变
    		// 编译报错: The final field FinalDemo.num cannot be assigned
    		// num = 2;
    		// 编译报错: The final field FinalDemo.name cannot be assigned
    		// name = "artisan";
    
    		// 引用对象,此引用无法指向别的对象,但可修改该对象的值
    		map.put("name", "小工匠");
    		log.info("name:{}", map.get("name"));
    		
    		
    		// 验证 方法参数被final修饰的情况
    		List<String> list = new ArrayList<>();
    		list.add("我是小工匠");
    		test2(list);
    		
    	}
    
    	// final修饰传递进来的变量基本类型,不可别改变
    	private void test(final int a) {
    		// 不能修改
    		// 编译报错: The final local variable a cannot be assigned. It must be blank and not using a compound assignment
    		// a = 2;
    		log.info("a:{}", a);
    	}
    
    	// final修饰方法传递进来的变量 引用对象,无法指向别的对象,但可修改该对象的值
    	private static void test2(final List<String> list) {
    		// 添加数据
    		list.add("我是artisan");
    		list.forEach(str ->{
    			log.info("数据:{}",str);
    		});
    	}
    
    }
    
    

    输出:

    在这里插入图片描述

    需要我们注意的是,final修饰引用类型时,虽然不能将引用再指向别的对象,但可修改该对象的值。 线程不安全


    使用JDK / Guava中提供的工具类创建不可变对象

    除了final可以定义不可变对象,java提供的Collections类,也可定义不可变对象。

    • JDK中的 Collections.unmodifiableXXX传入的对象一经初始化便无法修改,XXX可表示Collection、List、Set、Map等

    • 谷歌的Guava中的ImmutableXXX,XXX同样可表示Collection、List、Set、Map等


    Collections.unmodifiableXXX 示例 (线程安全)

    在这里插入图片描述

    执行后结果如下:

    在这里插入图片描述

    由此可见,用Collections.UnmodifiableMap修饰的对象是不可修改的,如果尝试修改对象的值,在程序运行时会抛出异常。


    跟下Collections.UnmodifiableMap的源码

    在这里插入图片描述

    继续看下UnmodifiableMap

    在这里插入图片描述

    主要是将一个新的集合的所有更新方法变为抛出异常


    Guava ImmutableXXX 示例 (线程安全)

    在这里插入图片描述

    package com.artisan.example.immutable;
    
    import com.artisan.anno.ThreadSafe;
    import com.google.common.collect.ImmutableList;
    import com.google.common.collect.ImmutableMap;
    import com.google.common.collect.ImmutableSet;
    
    
    @ThreadSafe
    public class GuavaImmutableSetDemo {
    
    	// 使用Guava中提供的类来定义不可变对象的集合
    	
    	// 不可变list
    	private final static ImmutableList<Integer> list = ImmutableList.of(1, 2, 3);
    	// 不可变的set
    	private final static ImmutableSet<Integer> set = ImmutableSet.copyOf(list);
    	// 不可变的map,需要以k/v的形式传入数据,即奇数位参数为key,偶数位参数为value
    	private final static ImmutableMap<String, String> map = ImmutableMap.of("k1", "v1", "k2","v2");
    	// 通过builder调用链的方式构造不可变的map
    	private final static ImmutableMap<String, String> map2 = ImmutableMap.<String, String>builder()
    																			.put("key1", "value1")
    																			.put("key2", "value2")
    																			.put("key3", "value3")
    																			.build();
    
    	public static void main(String[] args) {
    		
    		// 修改对象内的数据就会抛出UnsupportedOperationException异常
    		
    		// 不能添加新的元素 ,运行将抛出 java.lang.UnsupportedOperationException
    		list.add(4);
    
    		// 不能添加新的元素 ,运行将抛出 java.lang.UnsupportedOperationException
    		set.add(4);
    
    		// 不能添加新的元素 ,运行将抛出 java.lang.UnsupportedOperationException
    		map.put("k3", "v3");
    
    		// 不能添加新的元素 ,运行将抛出 java.lang.UnsupportedOperationException
    		map2.put("key4", "value4");
    	}
    }
    
    
    

    在这里插入图片描述

    上述代码是线程安全的,开发时如果我们的对象可以变为不可变对象,我们尽量将对象变为不可变对象,这样可以避免线程安全问题。


    代码

    https://github.com/yangshangwei/ConcurrencyMaster

    展开全文
  • 在上面的代码中,是使用类A的对象好,还是对象指针比较好呢?很多时候,我们都没有深刻考虑过这两种情况,似乎在一个类中 都可以满足我们的需求。这种问题在stackoverflow上当然有回复: t’s very

    引子:

    class A{};
    class B{
      public:
        B();
        ~B();
      private:
        A object_a;
        A * ptr_a;
    };

    在上面的代码中,是使用类A的对象好,还是对象指针比较好呢?

    很多时候,我们都没有深刻考虑过这两种情况,似乎在一个类中 都可以满足我们的需求。

    这种问题在stackoverflow上当然有回复:
    t’s very unfortunate that you see dynamic allocation so often. That just shows how many bad C++ programmers there are.
    非常不幸,你在代码中遇到这么多的动态内存分配,但这个只能说明有现在有太多不合格的 C++ 程序员。
    哭死

    In a sense, you have two questions bundled up into one. The first is when should we use dynamic allocation (using new)? The second is when should we use pointers?
    这么说吧,你的两个问题本质上是同个问题。第一个问题是,应该何时使用动态分配(使用 new 方法)?第二问题是,什么时候该使用指针?

    The important take-home message is that you should always use the appropriate tool for the job. In almost all situations, there is something more appropriate and safer than performing manual dynamic allocation and/or using raw pointers.
    最先要牢记的重点是,你应该根据实际需求选择合适的方法。 一般来说,使用定义对象的方式比起使用手工动态分配(或new指针)的方式会更加合理以及安全。

    It’s very unfortunate that you see dynamic allocation so often. That just shows how many bad C++ programmers there are.

    In a sense, you have two questions bundled up into one. The first is when should we use dynamic allocation (using new)? The second is when should we use pointers?

    The important take-home message is that you should always use the appropriate tool for the job. In almost all situations, there is something more appropriate and safer than performing manual dynamic allocation and/or using raw pointers.

    Dynamic allocation

    In your question, you’ve demonstrated two ways of creating an object. The main difference is the storage duration of the object. When doing Object myObject; within a block, the object is created with automatic storage duration, which means it will be destroyed automatically when it goes out of scope. When you do new Object(), the object has dynamic storage duration, which means it stays alive until you explicitly delete it. You should only use dynamic storage duration when you need it. That is, you should always prefer creating objects with automatic storage duration when you can.

    The main two situations in which you might require dynamic allocation:

    You need the object to outlive the current scope - that specific object at that specific memory location, not a copy of it. If you’re okay with copying/moving the object (most of the time you should be), you should prefer an automatic object.
    You need to allocate a lot of memory, which may easily fill up the stack. It would be nice if we didn’t have to concern ourselves with this (most of the time you shouldn’t have to), as it’s really outside the purview of C++, but unfortunately we have to deal with the reality of the systems we’re developing for.
    When you do absolutely require dynamic allocation, you should encapsulate it in a smart pointer or some other type that performs RAII (like the standard containers). Smart pointers provide ownership semantics of dynamically allocated objects. Take a look at std::unique_ptr and std::shared_ptr, for example. If you use them appropriately, you can almost entirely avoid performing your own memory management (see the Rule of Zero).

    动态分配
    你的提问中,所列出的两种分配对象方式的主要区别在于对象的生存期。通过 Object myObject 方式定义对象,对象的生存期是在其作用域内自维护(automatic storage),这个意味着程序离开对象的作用域之后,对象将被自动销毁。当通过 new Object() 方式分配对象时,对象的生存期是动态的,这个意味着若不显式地 detete 对象,对象将一直存在。你应该只在必要的时候使用动态分配对象。换句话说,只要有可能,你应该首选定义可自维护的对象。

    这里是两个常见需要动态分配对象的情况:

    分配不限制作用域的对象,对象存储在其特定的内存中,而不是在内存中存储对象的拷贝。如果对象是可以拷贝/移动的,一般情况下你应该选择使用定义对象的方式。
    定义的对象会消耗大量内存,这时可能会耗尽栈空间。如果我们永远不需要考虑这个问题那该多好(实际大部分情况下,我们真不需要考虑),因为这个本身已经超出 C++ 语言的范畴,但不幸的是,在我们实际的开发过程中却不得不去处理这个问题。
    当你确实需要动态分配对象时,应该将对象封装在一个智能指针(smart pointer)或其他提供RAII机制的类型中(类似标准的 container)。智能指针提供动态对象的所有权语义(ownership),具体可以看一下std::unique_ptr 和 std::shared_ptr 这两个例子。如果你使用得当,基本上可以避免自己管理内存(具参见 Rule of Zero)。

    Pointers

    However, there are other more general uses for raw pointers beyond dynamic allocation, but most have alternatives that you should prefer. As before, always prefer the alternatives unless you really need pointers.

    You need reference semantics. Sometimes you want to pass an object using a pointer (regardless of how it was allocated) because you want the function to which you’re passing it to have access that that specific object (not a copy of it). However, in most situations, you should prefer reference types to pointers, because this is specifically what they’re designed for. Note this is not necessarily about extending the lifetime of the object beyond the current scope, as in situation 1 above. As before, if you’re okay with passing a copy of the object, you don’t need reference semantics.
    You need polymorphism. You can only call functions polymorphically (that is, according to the dynamic type of an object) through a pointer or reference to the object. If that’s the behaviour you need, then you need to use pointers or references. Again, references should be preferred.
    You want to represent that an object is optional by allowing a nullptr to be passed when the object is being omitted. If it’s an argument, you should prefer to use default arguments or function overloads. Otherwise, you should prefer use a type that encapsulates this behaviour, such as boost::optional (or perhaps soon, std::optional - Edit std::optional is voted out of the current C++14 draft n3797).
    You want to decouple compilation units to improve compilation time. The useful property of a pointer is that you only require a forward declaration of the pointed-to type (to actually use the object, you’ll need a definition). This allows you to decouple parts of your compilation process, which may significantly improve compilation time. See the Pimpl idiom.
    You need to interface with a C library or a C-style library. At this point, you’re forced to use raw pointers. The best thing you can do is make sure you only let your raw pointers loose at the last possible moment. You can get a raw pointer from a smart pointer, for example, by using its get member function. If a library performs some allocation for you which it expects you to deallocate via a handle, you can often wrap the handle up in a smart pointer with a custom deleter that will deallocate the object appropriately.

    指针

    当然,不使用动态分配而采取原始指针(raw pointer)的用法也很常见,但是大多数情况下动态分配可以取代指针,因此一般情况应该首选动态分配的方法,除非你遇到不得不用指针的情况。

    1. 使用引用语义(reference semantics)的情况。有时你可能需要通过传递对象的指针(不管对象是如何分配的)以便你可以在函数中去访问/修改这个对象的数据(而不是它的一份拷贝),但是在大多数情况下,你应该优先考虑使用引用方式,而不是指针,因为引用就是被设计出来实现这个需求的。注意,采用这种方式,对象生存期依旧在其作用域内自维护。当然,如果通过传递对象拷贝可以满足要求的情况下是不需要使用引用语义。

    2. 使用多态的情况。通过传递对象的指针或引用调用多态函数(根据入参类型不同,会调用不同处理函数)。如果你的设计就是可以传递指针或传递引用,显然,应该优先考虑使用传递引用的方式。

    3. 对于入参对象可选的情况,常见的通过传递空指针表示忽略入参。如果只有一个参数的情况,应该优先考虑使用缺省参数或是对函数进行重载。要不然,你应该优先考虑使用一种可封装此行为的类型,比如 boost::optional (或者std::optional,已经在 C++ 14 草案 n3797 14 中发布 )。

    4. 通过解耦编译类型依赖减少编译时间的情况。使用指针的一个好处在于可以用于前向声名(forward declaration)指向特定类型(如果使用对象类型,则需要定义对象),这种方式可以减少参与编译的文件,从而显著地提高编译效率,具体可以看 Pimpl idiom 用法。

    5. 与C库或C风格的库交互的情况。此时只能够使用指针,这种情况下,你要确保的是指针使用只限定在必要的代码段中。指针可以通过智能指针的转换得到,比如使用智能指针的get成员函数。如果C库操作分配的内存需要你在代码中维护并显式地释放时,可以将指针封装在智能指针中,通过实现 deleter 从而可以有效的地释放对象。

    在函数形参中使用对象指针更好
    再看一个例子:

    void fun(Base b) { ... }
    void gun(Base* b) { ... }
    void hun(Base& b) { ... }
    
    Base b;
    fun(b);  // copies b, potentially expensive 
    gun(&b); // takes a pointer to b, no copying
    hun(b);  // regular syntax, behaves as a pointer

    Efficiency
    Passing objects to functions mean creating new copies of object.

    Working with objects from third party libraries.
    If your object belongs to a third party code and the authors intend the usage of their objects through pointers only (no copy constructors etc) the only way you can pass around this object is using pointers. Passing by value may cause issues. (Deep copy / shallow copy issues).

    if the object owns a resource and you want that the ownership should not be sahred with other objects.

    展开全文
  • arr.find(item=>item.children) 返回数组中包含有children属性的对象

    arr.find(item=>item.children)
    返回数组中包含有children属性的对象

    展开全文
  • 详解Python中的可哈希对象可哈希对象(二)

    千次阅读 多人点赞 2019-10-30 16:49:52
    前言:我们经常会听见很多的概念,哈希值,哈希表,可哈希对象可哈希对象,散列表,字典,映射,等等,那么这么多的概念后面到底又有什么区别和联系,它们的本质又是怎么样的,本此系列文章将针对这些概念进行...
  • /*查询出满足条件的对象item*/ const nameArr=[ {id:1,userName:"zhaoqian",age:27}, {id:2,userName:"sunli",age:23}, {id:3,userName:"zhouwu",age:25 }, {id:4,userName:"zhengwa...
  • 什么是面向对象

    万次阅读 多人点赞 2019-09-09 16:54:50
    说的最多的是new个对象,其实并知道什么是对象。以为对象就是一个class(类),并觉得有什么特殊。直到很久之后,面试官问到什么是OOP,嘴巴都是一个大O,OOP?WTF?那人厌恶的说到就是面向对象编程。我说:Java...
  • 一、对象 var obj = {}; obj[true] = "foo"; obj[3] = "bar"; obj[obj] = "baz"; obj["true"]; obj["3"]; obj["[object Object]"]; 二、数组也是对象 var ary = ["foo", 42, "bar"]; ary.baz = "baz"; ary....
  • Java可变对象

    千次阅读 2016-01-10 16:27:28
    可变对象是指一个对象的状态在对象被创建之后就不再变化。可变对象对于缓存是非常好的选择,因为你需要担心它的值会被更改。 创建一个可变类: 将类声明为final,所以它能被继承;将所有的成员声明...
  • 如题,我想要找到name="张三",所在的对象(符合条件的对象可能不止一个,只要符合都找出来),即结果是{ "name":"张三", "age":"18", "address":{ "city":"北京", "street":"长安街" } } 如果不用循环,请问...
  • 创建后状态能被修改的对象叫作可变对象可变对象天生就是线程安全的。它们的常量(变量)是在构造函数中创建的,既然它们的状态无法被修改,那么这些常量永远不会被改变——可变对象永远是线程安全的。 ...
  • updateNav (){ this.navList=[]; //设置对this的引用,在function回调里,this指向的并是Vue实例 var _this=this; this.getTabs().forEach(function(pane,index) { ...
  • 知道的java对象序列化的秘密

    万次阅读 2020-06-03 06:16:00
    你知道序列化可以使用代理吗?...每个java程序员都听说过序列化,要存储对象需要序列化,要在网络上传输对象要序列化,看起来很简单的序列化其实里面还隐藏着很多小秘密,今天本文将会为大家一一揭秘。
  • C语言真的能面向对象吗?

    千次阅读 2014-03-16 23:35:32
    在承认C语言无可争议的运行效率的同时,也总爱拿C语言具备面向对象血统的短板说事。当年在看这些的书的时候,我还觉得深以为然。但经过这些年的学习和见闻,我却越来越强烈地感到这种说法有失偏颇:C语言真的...
  • redis——对象

    千次阅读 多人点赞 2019-04-18 14:10:19
    redis肯定能直接使用这些数据结构来实现数据库,它用这些数据库建立了一个对象系统,包含: 字符串对象、列表对象、哈希对象、集合对象、有序集合对象 我们可以针对不同的使用场景,为对象设置多种分不同的数据...
  • 周六写一篇关于python 的博客(可变 :地址传递 可变:值传递)
  • Kubernetes对象模型

    万次阅读 2018-10-13 20:44:20
    Kubernetes对象 在之前的文章已经讲到了很多Kubernets对象,包括pod,service,deployment等等。Kubernets对象是一种持久化,表示集群状态的实体。它是一种声明式的意图的记录,一般使用yaml文件描述对象,它使用...
  • 一, 能创建对象的类抽象类(abstract)能创建对象。这个大家应该都知道,所以在这里就班门弄斧了。 简单回顾需要注意的几点: 包含抽象方法的类,必须声明为抽象类。 声明为抽象类的类,一定非要包含抽象...
  • Python Pandas中Dataframe对象,如何根据列值筛选满足条件的行,并且返回列的索引值,我们举栗子说明一下: 1.先创建一个dataframe变量df: df = pd.DataFrame(np.arange(16).reshape(4,4), #index = pd.date_...
  • 可迭代对象&迭代对象

    千次阅读 2018-09-18 18:05:39
    满足可迭代对象前提: 可以被循环的对象就是可迭代对象; 例如:str、list、tuple、set、dict、range、generator 可以使用比较高效的方式判断某个对象是否是可迭代对象 需要导入collections模块中的Iterable属性,...
  • java面向对象

    万次阅读 多人点赞 2018-08-21 16:51:59
    包括面向对象概念、类与对象的关系、封装、构造函数、this关键字、static关键字、单例设计模式、继承、多态、内部类、异常、包等java基础知识。 1、面向对象 面向对象是相对面向过程而言 面向对象和面向过程都是...
  • //如果满足条件的对象存在 User user = userList.stream().filter(t -> 1 == t.getId()).findAny().get(); System.out.println("have: " + user.toString()); //如果对象不存在,则会抛出异常:java.util....
  • 原先的工具类是不满足的,只能全部复制,所以又将原先的工具类做了修改。添加了对象合并的功能,同时还多设置了两个个参数,用一个boolean类型的参数来设定目标对象属性为null时是否覆盖,用一个set来设定例外的...
  • 浅析spring中创建的对象如何保证被回收 JVM通过可达性分析来判定对象是否存活。这个算法的基本思路就是通过一系列称为 GC Roots的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为...
  • js中那些方法改变原来的数组对象

    万次阅读 2015-10-21 09:59:07
    一、map方法 function fuzzyPlural(single) { var result = single.replace(/o/g, 'e'); //replace也不会修改原来数组的值,这里...四、filter,forEach,some,every(只要有一个元素不满足就会终止循环)等
  • jsp之九大内置对象与四大域对象

    万次阅读 多人点赞 2017-03-31 15:15:10
    如果每次我们在jsp页面中需要使用这些对象都要自己亲自动手创建就会特别的繁琐.SUN公司因此在设计jsp时,在jsp页面加载完毕之后自动帮开发者创建好了这些对象,开发者只需要使用相应的对象调用相应的方法即可....
  • js删除符合条件的数据(对象数组)

    千次阅读 2019-07-25 13:47:09
    一、删除符合条件的数据 数据如下 (把status等于1的数据删除) var list = [{ "amount": 10, "createTime": 1533010042926, "id": 14, "status": 0 }, { "amoun...
  • 了解并发编程中对象的共享

    万次阅读 2019-12-30 11:59:56
    我们不仅希望防止某个线程正在使用对象状态而另一个线程在同时修改该状态,而且希望确保当一个线程修改了对象状态后,其他线程能够看到发生的状态变化。如果没有同步,那么这种情况就无法实现,所以我们可以通过显示...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 951,238
精华内容 380,495
关键字:

对象满足不了自己