学习笔记:泛型、反射。

1.JAVA泛型

Java 泛型(generics) 是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。

Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常。

泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,或者是某个方法的返回值的类型,或者是参数类型。

class Person<E>{ 
    //E就是这个标识
    //E标识s的数据类型,该数据类型在定义Person对象的时候指定,即在编译期间就确定E是什么类型
    E s;
    
    public Person(E s){ // E也可以是参数类型
        this.s = s;
    }
    
    public E f(){  //返回类型使用E
        return s;
    }
}
//如果我们在定义Person对象的时候,指定类型为String,那么上述代码块中的E则表示String,即所有的E都可以用String替代.
Person<String> person = new Person<String>("篮网总冠军2022!");

//如果我们在定义Person对象的时候,指定类型为Integer,那么上述代码块中的E则表示Integer,即所有的E都可以用Integer替代.
Person<Integer> person = new Person<Integer>(2022);

/*Person<Integer> person = new Person<Integer>("篮网总冠军2022!");
如果我们写成这样子就会立马报错(也就是在编译期间报错),而不用非得等到你运行程序的时候才会报错,效率就提高了。
*/

1.1泛型使用细节

1.给泛型指向数据类型要求是 “引用类型”,不能是 “基本数据类型”。

2.在给泛型指定具体类型后,可以传入改类型或者其子类类型

public class Main {
    public static void main(String[] args) {
        Pig<A> pig1 = new Pig<A>(new A());
        Pig<A> pig2 = new Pig<A>(new B());//这里会报错 因为泛型指定了具体数据类型A  但是却传入了一个B的对象
    }
}
class A{}
class B{}
class Pig<E> {
    E e;
    
    public Pig(E e){
        this.e = e;
    }
}
public class Main {
    public static void main(String[] args) {
        Pig<A> pig1 = new Pig<A>(new A());
        Pig<A> pig2 = new Pig<A>(new B());
    }
}
class A{}
class B extends A{}
class Pig<E> {
    E e;
    public Pig(E e){
        this.e = e;
    }
}
//将class B{}修改成class B extends A{},即让B称为A的子类就不会报错了。
//因为此时既可以传入指定类型A 也可以传入指定类型A的子类类型B

3.泛型的使用形式.

ArrayList<Integer> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();  //可以用List接口来接收 “编译看左边、运行看右边” 

在实际开发中,我们往往简写:
未简写:ArrayList<Integer> list1 = new ArrayList<Integer>();
简写:ArrayList<Integer> list1 = new ArrayList<>();
如果我们这样写 List list3 = new ArrayList(); 默认给它的泛型是Object

1.2自定义泛型类

class Tiger<T, R, M> {
    String name;
    R r; //属性使用泛型
    M m;
    T t;
    
    /*
    static R r2;//这种写法报错
    public static void m1(M m){ //这种写法报错
    }
    因为静态是和类相关的,在类加载时,对象还没有创建,所以如果静态方法和静态属性使用了泛型,JVM就无法完成初始化。
    */
   
    //使用泛型的数组,不能初始化
    //T[] ts = new T[8];  这种写法就会报错,因为数组在 new 时不能确定 T 的类型,就无法在内存开空间
    //但是如果只是定义   T[] ts;   则是可以的。
    
    
    public Tiger(String name, R r, M m, T t) {  //构造器使用泛型
        this.name = name;
        this.r = r;
        this.m = m;
        this.t = t;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public R getR() {
        return r;
    }

    public void setR(R r) {  //方法使用泛型
        this.r = r;
    }

    public M getM() {  //返回类型使用泛型
        return m;
    }

    public void setM(M m) {
        this.m = m;
    }

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }
}

1.3自定义泛型接口

1)接口中,静态成员也不能使用泛型(这个和泛型类规定一定)

2)泛型接口的类型,在继承接口或者实现接口时确定

3)没有指定类型,默认为Object

1.4自定义泛型方法

基本语法:

修饰符 <T,R…> 返回类型 方法名(参数列表){

}

1)泛型方法可以定义在普通类中,也可以定义在泛型类中。


class Car{  //普通类
    public void run(){  //普通方法

    }

    public <T,R> void fly(T t,R r){  //泛型方法

    }
}



class Fish<T,R>{  //泛型类
    public void run(){  //普通方法

    }


    public <U,M> void eat(U u,M m){  //泛型方法

    }
    //泛型方法可以使用类声明的泛型,也可以使用自己声明的泛型
}

2)泛型方法被调用时,类型会确定。

Car car = new Car();
car.fly("越野",200);
//调用方法时,传入参数,编译器就会确定类型

3)“泛型方法“ 和 ”方法使用了泛型“ 的 区别

  public void hi(T t){  //hi方法使用了类声明的泛型 T
      
  }//注意区分泛型方法是怎么写的

1.5泛型的继承和通配符

1)泛型不具备继承性

List<Object> list = new ArrayList<String>();//这样写是不对的
//虽然String是Object的子类

2)

  • <?>:支持任意泛型类型
  • <? extends A>:支持A类以及A类的子类,规定了泛型的上限;
  • <? super A>:支持A类以及A类的父类,不限于直接父类,规定了泛型的下限;
public class Main {
    public static void main(String[] args) {
        List<Object> list1 = new ArrayList<>();
        List<String> list2 = new ArrayList<>();
        List<AA> list3 = new ArrayList<>();
        List<BB> list4 = new ArrayList<>();
        List<CC> list5 = new ArrayList<>();
        
        printCollection1(list1);//√
        printCollection1(list2);//√
        printCollection1(list3);//√
        printCollection1(list4);//√
        printCollection1(list5);//√
        
        printCollection2(list1);//×
        printCollection2(list2);//×
        printCollection2(list3);//√
        printCollection2(list4);//√
        printCollection2(list5);//√
        
        printCollection3(list1);//√
        printCollection3(list2);//×
        printCollection3(list3);//√
        printCollection3(list4);//×
        printCollection3(list5);//×
    }
    
    public static void printCollection1(List<?> c){
        for (Object object : c){
            System.out.println(object);
        }
    }
    
    public static void printCollection2(List<? extends AA> c){
        for (Object object : c){
            System.out.println(object);
        }
    }
    
    public static void printCollection3(List<? super AA> c){
        for (Object object : c){
            System.out.println(object);
        }
    }
}

class AA{
}

class BB extends AA {
}

class CC extends BB{
}

2.反射

通过外部文件配置,在不修改源码的情况下,来控制程序,也符合设计模式的开闭原则。

2.1反射机制

反射机制允许程序在执行期间借助于ReflectionAPI取得任何类的内部信息(比如成员变量、构造器、成员方法等),并能操作对象的属性及方法。反射在设计模式和框架底层都会用到。

加载完类之后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象),这个Class对象包含了类的完整结构信息,通过这个Class对象得到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以形象的称之为:反射。

反射相关的主要类:

  1. java.lang.Class:代表一个类,Class对象表示某个类加载后在堆中的对象。
  2. java.lang.reflect.Method:代表类的方法,Method对象表示某个类的方法
  3. java.lang.reflect.Field:代表类的成员变量,Field对象表示某个类的成员变量
  4. java.lang.reflect.Constructor:代表类的构造方法,Constructor对象表示构造器

反射优点和缺点:

优点:可以动态的创建和使用对象(也是框架底层核心),使用灵活,没有反射机制,框架技术就失去底层支撑。

缺点:使用反射基本是解释执行,对执行速度有影响。

反射调用优化—关闭访问检查:

1.Method和Field、Constructor对象都有setAccessible()方法;
2.setAccessible作用是启动和禁用访问安全检查的开关
3.参数值为true表示反射的对象在使用时取消访问检查,提高反射的效率,参数值为false表示反射的对象执行访问检查。

2.2 Class类

Class类对象不是new出来的,而是系统创建的。

对于某个类的Class类对象,在内存中只有一份,因为类只加载一次 。

每个类的实例都会记得自己是由哪个Class实例所生成。

通过Class对象可以完整的得到一个类的完整结构,通过一系列API。

Class对象是存放在堆上的。

Class类常用方法:

Car.java文件

public class Car {
    public String brand = "宝马";
    public int price = 500;
    public String color = "白色";

    @Override
    public String toString() {
        return "Car{" +
                "brand='" + brand + '\'' +
                ", price=" + price +
                ", color='" + color + '\'' +
                '}';
    }
}
public class Class01 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {

        String classAllPath = "com.company.Car";

        //1.获取到 Car类 对应的 Class对象
        Class cls = Class.forName(classAllPath);

        //2.输出 cls
        System.out.println(cls);//显示cls对象是哪个类的Class对象
        System.out.println(cls.getClass());//输出cls运行类型

        //3.得到 包名
        System.out.println(cls.getPackage().getName());

        //4.得到 全类名
        System.out.println(cls.getName());

        //5.通过 cls 创建一个对象实例
        Car car = (Car)cls.newInstance();
        System.out.println(car);

        //6.通过反射获取属性
        Field brand = cls.getField("brand");
        System.out.println(brand.get(car));

        //7.通过反射给属性赋值
        brand.set(car,"越野");
        System.out.println(brand.get(car));

        //8.得到所有的属性
        System.out.println("==========所有的字段属性==========");
        Field[] fields = cls.getFields();
        for(Field f : fields){
            System.out.println(f.getName());
        }
    }
}
/*
class com.company.Car
class java.lang.Class
com.company
com.company.Car
Car{brand='宝马', price=500, color='白色'}
宝马
越野
==========所有的字段属性==========
brand
price
color
*/

2.3 获取Class类对象

1.前提:

已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException异常。

应用场景:多用于配置文件,读取类全路径,加载类。

String classAllPath = "com.company.Car";
//"com.company.Car" 是类的全类名,这里我直接写出来了,一般我们都是通过一些方法读取配置文件得到类的全路径
Class cls1 = Class.forName(classAllPath);
System.out.println(cls1);
//输出class com.company.Car

2.前提:

若已知具体的类,通过类的class获取,该方式最为安全可靠,程序性能最高。

应用场景:多用于参数传递,比如通过反射得到对应构造器对象。 ——————类名.class

Class cls2 = Car.class;
System.out.println(cls2);
//输出class com.company.Car

3.前提:

已知某个类的实例,调用该实例的getClass()方法获取Class对象。

应用场景:通过创建好的对象,获取Class对象。

Car car = new Car();
Class cls3 = car.getClass();
System.out.println(cls3);
//输出class com.company.Car

4.通过类加载器获取到类的Class对象。

//先得到类加载器
ClassLoader classLoader = car.getClass().getClassLoader();
//通过类加载器得到Class对象
Class cls4 = classLoader.loadClass(classAllPath);
System.out.println(cls3);
//输出class com.company.Car
//cls1、cls2、cls3、cls4其实是同一个对象
  System.out.println(cls1.hashCode());
  System.out.println(cls2.hashCode());
  System.out.println(cls3.hashCode());
  System.out.println(cls4.hashCode());

/*
hashcode都相同
460141958
460141958
460141958
460141958
*/

5.基本数据(int、char、boolean、float、double、byte、long、short)按如下方式得到Class类对象

        Class<Integer> integerClass = int.class;
        Class<Character> characterClass = char.class;
        System.out.println(integerClass);
        System.out.println(characterClass);
/*输出:
int
char
*/

6.基本数据类型对应的包装类,可以通过.TYPE得到Class类对象

        Class<Integer> type1 = Integer.TYPE;
        Class<Character> type2 = Character.TYPE;
        System.out.println(type1);
        System.out.println(type2);
/*输出:
int
char
*/

2.4 类加载

反射机制是java实现动态语言的关键,也就是通过反射实现类动态加载。

1.静态加载:编译时加载相关的类,如果没有则报错,依赖性太强。

2.动态记载:运行时加载需要的类,如果运行时不用该类,则不报错,降低了依赖性。

在这里插入图片描述
在这里插入图片描述

类加载五个阶段:

  • 1.加载阶段:JVM在该阶段的主要目的是将字节码从不同的数据源(可能是class文件、也可能是jar包,甚至网络)转化为二进制字节流加载到内存中,并生成一个代表该类的java.lang.Class对象。
  • 2.连接阶段–验证:目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。包括:文件格式验证(是否以魔数oxcafebabe开头)、元数据验证、字节码验证和符号引用验证。可以考虑使用 -Xverify:none 参数来关闭大部分的类验证措施,缩短虚拟机类加载的时间。
  • 2.连接阶段–准备:JVM会在该阶段对静态变量,分配内存并默认初始化。这些变量所使用的内存都将在方法区中进行分配。
class A{
    public int n1 = 10;
    public static int n2 = 20;
    public static final int n3 = 30;
}
//1. n1是实例属性,不是静态变量,因此在准备阶段,是不会分配内存的;
//2. n2是静态变量,分配内存n2 是默认初始化为0,而不是20
//3. n3是static final 是常量,它和静态变量不一样,因为一旦赋值就不变 n3 = 30
  • 2.连接阶段–解析: 虚拟机将常量池内的符号引用替换为直接引用的过程。
  • 3.Initialization(初始化):到初始化阶段,才真正开始执行类中定义的Java程序代码,此阶段是执行clinit()方法的过程。 clinit()方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中的所有静态变量的赋值动作和静态代码块的语句,并进行合并。 虚拟机会保证一个类的clinit()方法在多线程环境中被正确的加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的clinit()方法,其他线程都需要去阻塞等待,直到活动线程clinit()方法完毕。

​ 直接使用类的静态属性,也会导致类的加载。

2.5 通过反射获取类的结构信息 API多看就记住了 查查手册文档

第一组:java.lang.Class类

public class ReflectionUtils {
    public static void main(String[] args){

    }
    @Test
    public void api_01() throws ClassNotFoundException {
        //得到Class对象
        Class personCls = Class.forName("com.company.Person");
        System.out.println("===============================");



        //getName:获取全类名
        System.out.println(personCls.getName());//com.company.Person
        System.out.println("===============================");



        //getSimpleName:获取简单类名
        System.out.println(personCls.getSimpleName());//Person
        System.out.println("===============================");



        //getFields:获取所有public修饰的属性,包含本类以及父类的
        Field[] fields = personCls.getFields();
        for (Field field : fields) {
            System.out.println(field.getName());
        }
        System.out.println("===============================");



        //getDeclaredFields:获取本类中所有属性
        Field[] declaredFields  = personCls.getDeclaredFields();
        for (Field declaredField: declaredFields) {
            System.out.println("本类中所有属性:" + declaredField.getName());
        }
        System.out.println("===============================");



        //getMethods:获取所有public修饰的方法,包含本类以及父类的
        Method[] methods = personCls.getMethods();
        for(Method method : methods){
            System.out.println("本类以及本类所有父类的方法:" + method.getName());
        }
        System.out.println("===============================");


        //getDeclaredMethods:获取本类中所有方法
        Method[] declaredMethods = personCls.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println("本类所有方法:" + declaredMethod.getName());
        }
        System.out.println("===============================");



        //getConstructors:获取本类所有public修饰的构造器,
        Constructor[] constructors = personCls.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println("本类以及父类的构造器:" + constructor.getName());
        }
        System.out.println("===============================");




        //getDeclaredConstructors:获取本类中所有构造器
        Constructor[] declaredConstructors = personCls.getDeclaredConstructors();
        for (Constructor declaredConstructor : declaredConstructors) {
            System.out.println("本类所有的构造器:" + declaredConstructor.getName());
        }
        System.out.println("===============================");



        //getPackage:以Package形式返回 包信息
        System.out.println(personCls.getPackage());
        System.out.println("===============================");




        //getSuperClass:以Class形式返回父类信息
        Class superclass = personCls.getSuperclass();
        System.out.println("父类的class对象:" + superclass);
        System.out.println("===============================");




        //getInterfaces:以Class[]形式返回接口信息
        Class[] interfaces = personCls.getInterfaces();
        for (Class anInterface : interfaces) {
            System.out.println("接口信息:" + anInterface);

        }
        System.out.println("===============================");



        //getAnnotations:以Annotation[] 形式返回注解信息
        Annotation[] annotations = personCls.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println("注解信息:" + annotation);
        }
        System.out.println("===============================");

    }
}

class A{
    public String hobby;
    public void hi(){
        System.out.println("hi....");
    }

    public A(){}
}


interface IA{

}

interface IB{

}


@Deprecated
class Person extends A implements IA,IB{
    //属性
    public String name;
    protected int age;
    String job;
    private double sal;

    //构造器
    public Person(){}
    public Person(String name){}
    private Person(String name,int age){}//私有的


    //方法
    public void m1(){

    }

    protected void m2(){

    }

    void m3(){

    }

    private void m4(){

    }
    /*
    四种访问权限:
    private:“私有”,被其修饰的属性和方法仅能被本类对象访问;
    default:“缺省”默认的,被其修饰的属性和方法允许同一个包下访问;
    protected:“受保护的”,被其修饰的属性和方法允许被不同包下的子类访问;
    public:“公共”,被其修饰的属性和方法可以被任何对象访问;
     */
}

第二组:java.lang.reflect.Field类

  1. getModifiers:以int形式返回修饰符,【说明:默认修饰符是0,public是1,private是2,protected是4,static是8,final是16】
  2. getType:以Class形式返回类型。
  3. getName:返回属性名

第三组:java.lang.reflect.Method类

  1. getModifiers:以int形式返回修饰符,【说明:默认修饰符是0,public是1,private是2,protected是4,static是8,final是16】
  2. getReturnType: 以Class形式获取返回类型
  3. getName:返回方法名
  4. getParameterTypes:以Class[]返回参数类型数组

第四组:java.lang.reflect.Constructor类

  1. getModifiers:以int形式返回修饰符
  2. getName:返回构造器名(全类名)
  3. getParameterTypes:以Class[]返回参数类型数组

2.6 通过反射创建对象实例

package com.company;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class ReflectCreateInstance {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        //1.先获取User类的Class对象
        Class<?> userClass = Class.forName("com.company.User");


        //2.通过public的无参构造器创建实例
        Object o = userClass.newInstance();
        System.out.println(o);


        //3.通过public的有参构造器创建实例
        //先得到对应的构造器
        Constructor<?> constructor = userClass.getConstructor(String.class);
        //然后创建实例,并传入实参
        Object KD_KI = constructor.newInstance("Champion");
        System.out.println(KD_KI);



        //4.通过非public的有参构造器创建实例
        //先得到private的构造器对象
        Constructor<?> declaredConstructor = userClass.getDeclaredConstructor(int.class, String.class);
        //创建实例
        declaredConstructor.setAccessible(true);//暴(力)破(解),使用反射可以访问private构造器
        Object kyrie = declaredConstructor.newInstance(100, "凯里欧文");
        System.out.println(kyrie);



    }
}

class User{
    private int age;
    private String name;
    public User(){

    }

    public User(String name){
        this.name = name;
    }

    private User(int age, String name) {
        this.age = age;
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}


/*
User{age=0, name='null'}
User{age=0, name='Champion'}
User{age=100, name='凯里欧文'}

*/

2.7 通过反射访问类中的成员

1.反射操作属性

package com.company;

import java.lang.reflect.Field;

//演示反射操作属性
public class ReflectAccessProperty {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {

        //1.得到Student类对应的Class对象
        Class<?> stuClass = Class.forName("com.company.Student");
        //2.创建对象
        Object o = stuClass.newInstance();


        //3.使用反射得到age属性对象
        Field age = stuClass.getField("age");
        age.set(o,30);
        System.out.println(o);
        System.out.println(age.get(o));


        //4.使用反射操作name 属性   name为私有静态属性
        Field name = stuClass.getDeclaredField("name");
        //对name进行爆破
        name.setAccessible(true);
        name.set(o,"欧文");
        //name.set(null,"杜兰特");//因为name是static属性,因此 o 也可以写作null
        System.out.println(o);
        System.out.println(name.get(o));//获取属性值
        //System.out.println(name.get(null));//这种写法一定要求name是static的
        
    }
}

class Student{
    public int age;
    private static String name;

    public Student(){

    }

    @Override
    public String toString() {
        return "Student [age=" + age + ", name=" + name + "]";
    }
}

2.通过反射询问方法

package com.company;


//演示反射调用方法
public class ReflectAccessProperty {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
        
        

        //1.得到Boss类对应的Class对象
        Class<?> bossClass = Class.forName("com.company.Boss");
        //2.创建对象
        Object o = bossClass.newInstance();


        //3.调用public的hi方法
        //3.1得到hi方法对象
        Method hi = bossClass.getMethod("hi",String.class);
        //3.2 调用
        hi.invoke(o,"篮网总冠军!");
        //System.out.println(o);



        //4.调用private static方法
        //4.1 得到say方法对象
        Method say = bossClass.getDeclaredMethod("say", int.class, String.class, char.class);
        //4.2因为 say方法是private,所以需要爆破
        say.setAccessible(true);
        System.out.println(say.invoke(say,33,"杜兰特",'男'));
        //4.3 因为say方法是static的,还可以这样调用
        System.out.println(say.invoke(null,33,"杜兰特",'男'));


        //5.反射中如果方法有返回值,统一返回object  但是他运行类型和方法定义的返回类型是一致的
        Object reVal = say.invoke(null,33,"杜兰特",'男' );
        System.out.println("reVal的运行类型=" + reVal.getClass());

    }
}

class Boss{
    public int age;
    private static String name;

    public Boss(){

    }

    private static String say(int n, String s,char c){
        return n + "   " + s + "   " + c;
    }


    public void hi(String s) {
        System.out.println("hi  " + s);
    }
}

11.其他问题

11.1 Java实体类如果不重写toString方法,会如何?

例1:未重写toString方法

public class Main {
    public static void main(String[] args) {
        HashSet<Student> students = new HashSet<Student>();
        students.add(new Student("jack",18));
        students.add(new Student("Tom",133));
        students.add(new Student("irving",11));

        for(Student o : students){
            System.out.println(o);
        }
        
    }
}

class Student{
    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
//输出结果为
/*
com.company.Student@74a14482
com.company.Student@4554617c
com.company.Student@1b6d3586

未重写时,该类默认继承Object,进行输出时调用的就是Object类里的toString方法;
该方法会返回一个字符串,该字符串由类名(对象是该类的一个实例)、标记符“@”和此对象哈希码的无符号十六进制表示组成。

虽然我们写的输出是:System.out.println(o);
而不是System.out.println(o.toString());
但是这两种写法得到的结果是一样的,因为第一种写法实际上 “隐式调用”了 toString() 方法。
*/

例2:重写toString方法

public class Main {
    public static void main(String[] args) {
        HashSet<Student> students = new HashSet<Student>();
        students.add(new Student("jack",18));
        students.add(new Student("Tom",133));
        students.add(new Student("irving",11));

        for(Student o : students){
            System.out.println(o);
        }

    }
}

class Student{
    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
//输出结果为
/*
Student{name='irving', age=11}
Student{name='Tom', age=133}
Student{name='jack', age=18}
*/
//输出的格式我们可以在toString方法里进行修改,这里我们默认使用idea的生成方法生成的格式。

nts = new HashSet();
students.add(new Student(“jack”,18));
students.add(new Student(“Tom”,133));
students.add(new Student(“irving”,11));

    for(Student o : students){
        System.out.println(o);
    }

}

}

class Student{
private String name;
private int age;

public Student(String name, int age) {
    this.name = name;
    this.age = age;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public int getAge() {
    return age;
}

public void setAge(int age) {
    this.age = age;
}

@Override
public String toString() {
    return "Student{" +
            "name='" + name + '\'' +
            ", age=" + age +
            '}';
}

}
//输出结果为
/*
Student{name=‘irving’, age=11}
Student{name=‘Tom’, age=133}
Student{name=‘jack’, age=18}
*/
//输出的格式我们可以在toString方法里进行修改,这里我们默认使用idea的生成方法生成的格式。
























































  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值