Java学习-1

1.java的类和对象

类是对象的蓝图或模板,它定义了对象的属性和行为。类可以看作是一种自定义的数据类型,描述了具有相同特征和行为的对象。

类的组成部分:

  • 属性(成员变量):类中的变量,用于描述对象的状态或特征。例如,一个Car类可能有colorbrandspeed等属性。
  • 方法(成员函数):类中的函数,用于定义对象的行为或操作。例如,Car类可以有accelerate()brake()等方法。
  • 构造方法(Constructor):用于创建对象时初始化对象的状态。构造方法与类名相同,没有返回类型。
  • 代码块:静态代码块和实例代码块,用于在类加载或对象创建时执行一些操作。
  • 内部类:定义在类内部的类。

对象是类的实例,是根据类的定义创建的具体实体。每个对象都有自己的状态(属性值)和行为(方法)。

使用new关键字可以创建类的对象。创建对象时,会调用类的构造方法进行初始化

面向对象的特性

Java的面向对象编程有四大特性:

  1. 封装(Encapsulation):将数据(属性)和行为(方法)封装在类中,隐藏内部实现细节,只暴露必要的接口。
  2. 继承(Inheritance):子类可以继承父类的属性和方法,实现代码复用和扩展。
  3. 多态(Polymorphism):同一个方法在不同对象中有不同的实现方式。
  4. 抽象(Abstraction):通过抽象类和接口定义通用的行为,隐藏复杂的实现细节。

当在一个源文件中定义多个类,并且还有import语句和package语句时,要特别注意这些规则。

  • 一个源文件中只能有一个 public 类
  • 一个源文件可以有多个非 public 类
  • 源文件的名称应该和 public 类的类名保持一致。例如:源文件中 public 类的类名是 Employee,那么源文件应该命名为Employee.java。
  • 如果一个类定义在某个包中,那么 package 语句应该在源文件的首行。
  • 如果源文件包含 import 语句,那么应该放在 package 语句和类定义之间。如果没有 package 语句,那么 import 语句应该在源文件中最前面。
  • import 语句和 package 语句对源文件中定义的所有类都有效。在同一源文件中,不能给不同的类不同的包声明。

2.JAVA包

Java包是Java语言中一种非常重要的组织代码的方式。可以将包理解为文件夹,用于组织和管理相关的类和接口。就像我们用电脑的文件夹来整理文件一样,Java包用来整理Java代码文件,使其结构清晰,易于管理和维护。

从概念上讲,Java包主要有以下几个方面的作用:

  1. 命名空间管理 (Namespace Management):
    • 在Java开发中,随着项目规模的增大,可能会出现类名冲突的问题。比如,你可能在不同的地方定义了两个都叫做 MyClass 的类。如果没有包,Java编译器就无法区分你要使用的是哪个 MyClass
    • 包通过创建唯一的命名空间来解决这个问题。每个包都代表一个独立的命名空间,在同一个包内的类名是唯一的。即使不同的包中存在同名的类,由于它们属于不同的命名空间,Java编译器也能通过包名来区分它们,从而避免了类名冲突。
    • 例如,你可以创建一个名为 com.example.myapp.ui 的包来存放用户界面相关的类,再创建一个名为 com.example.myapp.data 的包来存放数据处理相关的类。这样,即使两个包中都有一个名为 Button 的类,由于包名不同 (com.example.myapp.ui.Buttoncom.example.myapp.data.Button),它们也是不同的类。
  2. 代码组织和管理 (Code Organization and Management):
    • 大型Java项目通常包含成千上万个类和接口。如果没有包来组织代码,所有的类都散落在同一个目录下,这将非常混乱,难以维护和管理。
    • 包可以将功能相关的类和接口组织在一起,形成逻辑上的模块。例如,可以将所有处理输入/输出的类放在 java.io 包中,将所有处理集合的类放在 java.util 包中。
    • 这种模块化的组织方式使得代码结构更加清晰,易于查找、理解、重用和维护。开发者可以更容易地找到需要的类,也更容易理解代码的功能和结构。
  3. 访问控制 (Access Control):
    • Java包提供了一种包级别的访问控制机制。在Java中,除了 publicprivateprotected 这三种常用的访问修饰符外,还有一种默认的访问修饰符(也称为包私有或package-private)
    • 当一个类成员(例如,字段、方法、构造器)没有使用任何访问修饰符时,它的访问权限就是包私有。这意味着只有同一个包内的类才能访问这个成员,不同包的类无法直接访问。
    • 包级别的访问控制可以帮助开发者隐藏实现细节限制不必要的访问,从而提高代码的安全性和模块化程度。

如何创建和使用Java包:

  • 创建包: 要创建一个Java包,你需要在你的Java源文件(.java 文件)的第一行使用 package 语句声明包名。包名通常采用反向域名的格式,例如 com.example.myapp。例如:

    package com.example.myapp;
    
    public class MyClass {
      // ... 类的内容 ...
    }
  • 目录结构和包名: Java包的命名和目录结构是紧密相关的。包名中的每一部分都对应着文件系统中的一个目录层级。例如,包名 com.example.myapp 就对应着目录结构 com/example/myapp/。你的Java源文件应该放在与包名对应的目录下。

    • 例如,如果你的包名是 com.example.myapp,那么 MyClass.java 文件应该放在 com/example/myapp/ 目录下。
    • 编译器会根据包名和目录结构来查找和组织类文件。
  • 导入包: 当你想在一个类中使用来自其他包的类时,你需要使用 import 语句导入目标类所在的包。有两种导入方式:

    • 导入单个类: 使用 import 包名.类名; 语句导入指定的类。例如:
    import java.util.ArrayList; // 导入 java.util 包中的 ArrayList 类
    
    public class MyClass {
        public static void main(String[] args) {
            ArrayList list = new ArrayList<>(); // 可以直接使用 ArrayList 类
            // ...
        }
    }
    • 导入整个包: 使用 import 包名.*; 语句导入整个包中的所有类。例如:
    import java.util.*; // 导入 java.util 包中的所有类
    
    public class MyClass {
        public static void main(String[] args) {
            ArrayList list = new ArrayList<>(); // 可以直接使用 ArrayList 类
            HashMap map = new HashMap<>(); // 可以直接使用 HashMap 类
            // ...
        }
    }

    注意: 虽然导入整个包很方便,但有时会降低代码的可读性,并且可能增加编译时间。建议只导入你真正需要的类

  • 默认包 (Default Package): 如果你的Java源文件没有使用 package 语句声明包名,那么该文件中的类就属于默认包。默认包是一个匿名的包,它没有名字。

    • 不建议使用默认包进行大型项目开发,因为它会使代码难以组织和管理,并且容易造成命名冲突。通常只在小型示例程序或学习代码中使用默认包。
    • 在默认包中的类,只能被同一个默认包中的类访问,不同包的类无法访问默认包中的类。

Java标准库中的包 (Predefined/Standard Java Packages):

Java标准库提供了大量的预定义包,也称为标准Java包Java API 包,这些包包含了各种各样的类和接口,用于完成各种常见的任务。这些包极大地扩展了Java的功能,开发者可以直接使用这些包中的类来构建应用程序,而无需从零开始编写所有代码。

  • 避免命名冲突: 通过创建唯一的命名空间,防止类名冲突。
  • 组织代码结构: 将相关的类和接口组织在一起,提高代码的模块化和可读性。
  • 代码重用: 包使得代码更易于重用,开发者可以利用已有的包来构建新的应用程序。
  • 访问控制: 提供包级别的访问控制,增强代码的安全性和模块化程度。
  • 简化开发: Java标准库提供了大量的预定义包,极大地简化了开发过程。

3.JAVA基本数据类型

变量就是申请内存来存储值。也就是说,当创建变量的时候,需要在内存中申请空间。

内存管理系统根据变量的类型为变量分配存储空间,分配的空间只能用来储存该类型数据

数据类型 默认值
int 0
long 0L
short 0
char ‘\u0000′(空字符)
byte 0
float 0.0f
double 0.0d
boolean false
引用类型(类、接口、数组) null

Java中的引用类型 (Reference Types)

Java中的引用类型 (Reference Types) 是Java语言中数据类型的一个重要组成部分,与基本类型 (Primitive Types) 相对。 理解引用类型对于掌握Java内存管理、对象操作以及面向对象编程至关重要。

核心概念:引用 vs. 对象

引用类型的核心在于 "引用" 这个词。引用 (Reference) 本身不是对象,而是一个指向对象在内存中位置的地址。 你可以把引用想象成一个遥控器,而对象就是被遥控的电视机。遥控器本身不是电视机,但通过遥控器你可以控制电视机。

关键点:

  • 引用变量存储的是对象的内存地址,而不是对象本身的数据。
  • 多个引用变量可以指向同一个对象。 就像多个遥控器可以控制同一台电视机。
  • 对对象的操作是通过引用进行的。 你通过遥控器来换台、调音量,而不是直接去碰电视机。

Java 中的引用类型主要包括:

  1. 类 (Class):

    • 这是最常见的引用类型。你自定义的每一个类都定义了一个新的引用类型。
    • 例如: String, Date, Scanner, 以及你自定义的 Person, Car, Student 等类都是引用类型。
    • 当你声明一个类类型的变量时,你创建了一个引用变量,它可以指向该类的对象。
    String str; // 声明一个 String 类型的引用变量 str
    str = new String("Hello"); // 创建一个新的 String 对象,并将它的地址赋值给 str
  2. 接口 (Interface):

    • 接口也定义了一种引用类型。接口本身不能被实例化 (不能 new 一个接口),但接口类型的变量可以指向实现了该接口的类的对象。
    • 例如: List, Set, Map, Comparable 等都是接口类型。
    List list; // 声明一个 List 接口类型的引用变量 list
    list = new ArrayList<>(); // 创建一个 ArrayList 对象 (实现了 List 接口),并将它的地址赋值给 list
  3. 数组 (Array):

    • 数组也是引用类型,即使数组存储的是基本类型的数据。
    • 数组变量存储的是数组对象在内存中的起始地址。
    int[] numbers; // 声明一个 int 数组类型的引用变量 numbers
    numbers = new int[5]; // 创建一个包含 5 个 int 元素的数组对象,并将它的地址赋值给 numbers
  4. 枚举 (Enum):

    • 枚举类型也是引用类型,它是一种特殊的类,用于定义一组命名的常量。
    enum Color { RED, GREEN, BLUE }
    Color myColor; // 声明一个 Color 枚举类型的引用变量 myColor
    myColor = Color.RED; // 将 Color 枚举类型的常量 RED 的引用赋值给 myColor

引用类型与基本类型的对比:

特性 基本类型 (Primitive Types) 引用类型 (Reference Types)
数据存储 直接存储值 存储对象的内存地址 (引用)
内存分配 在栈 (Stack) 中分配 对象在堆 (Heap) 中分配,引用在栈或堆中
默认值 有默认值 (如 int0, booleanfalse) 默认值为 null
大小 大小固定 (例如 int 始终是 4 字节) 大小不固定,取决于对象内容
传递方式 按值传递 (Pass-by-value) 按引用传递 (Pass-by-reference 的值)
类型 byte, short, int, long, float, double, char, boolean 类, 接口, 数组, 枚举

内存分配:堆 (Heap) 和 栈 (Stack)

  • 堆 (Heap): 所有引用类型的对象都存储在堆内存中。堆内存是动态分配的,Java 虚拟机 (JVM) 在运行时根据需要分配堆内存给对象。堆内存由垃圾回收器 (Garbage Collector) 自动管理。
  • 栈 (Stack): 栈内存主要用于存储基本类型的变量和引用类型的引用变量 (局部变量)。栈内存是后进先出 (LIFO) 的,方法调用时会在栈中创建栈帧,方法执行完毕栈帧会被弹出。

引用类型变量的声明和初始化:

  1. 声明: 声明引用类型变量时,需要指定变量的类型 (类名、接口名、数组类型等) 和变量名。

    ClassName variableName;
    InterfaceName variableName;
    DataType[] variableName;
    EnumName variableName;
  2. 初始化: 引用类型变量在声明后,默认值为 null。要使引用变量指向一个实际的对象,需要使用 new 关键字创建对象,并将返回的对象引用赋值给变量。

    variableName = new ClassName(constructorArguments); // 创建类的对象
    variableName = new DataType[arraySize]; // 创建数组对象
    variableName = EnumName.CONSTANT_NAME; // 枚举类型的常量已经是对象引用

    也可以将一个已经指向对象的引用变量赋值给另一个引用变量:

    String str1 = new String("Hello");
    String str2 = str1; // str2 和 str1 指向同一个 String 对象

null 引用:

  • null 是一个特殊的字面量,表示引用变量没有指向任何对象
  • 引用类型变量的默认值就是 null
  • 如果尝试通过 null 引用访问对象的成员 (例如调用方法或访问字段),会抛出 NullPointerException (空指针异常)。这是Java程序中常见的运行时错误。

引用传递 (按引用传递的值 – Pass-by-reference value):

Java 中对于引用类型,实际上是 按引用传递的值 (Pass-by-reference value) 或者更准确地说,按共享对象传递 (Pass-by-sharing)。 这意味着:

  • 当将引用类型变量作为参数传递给方法时,方法接收到的是引用变量值的副本
  • 这个副本仍然指向与原始引用变量相同的对象
  • 因此,在方法内部通过引用副本修改对象的内容,会影响到方法外部通过原始引用变量访问到的对象。
  • 但是,如果在方法内部改变引用变量副本的指向 (例如让它指向一个新的对象或 null),不会影响到原始引用变量的指向

示例:

class Person {
    String name;
    Person(String name) {
        this.name = name;
    }

    void changeName(String newName) {
        this.name = newName;
    }
}

public class ReferenceTypeExample {
    public static void main(String[] args) {
        Person person1 = new Person("Alice");
        Person person2 = person1; // person2 和 person1 指向同一个 Person 对象

        System.out.println("person1's name: " + person1.name); // 输出: person1's name: Alice
        System.out.println("person2's name: " + person2.name); // 输出: person2's name: Alice

        person2.changeName("Bob"); // 通过 person2 修改对象的名字

        System.out.println("person1's name after change through person2: " + person1.name); // 输出: person1's name after change through person2: Bob  (person1 的名字也被改变了)
        System.out.println("person2's name after change: " + person2.name); // 输出: person2's name after change: Bob

        person2 = new Person("Charlie"); // person2 指向新的 Person 对象 (但 person1 仍然指向原来的对象)

        System.out.println("person1's name after person2 points to a new object: " + person1.name); // 输出: person1's name after person2 points to a new object: Bob (person1 的名字仍然是 Bob)
        System.out.println("person2's name after pointing to a new object: " + person2.name); // 输出: person2's name after pointing to a new object: Charlie
    }
}

== 运算符和 equals() 方法:

  • == 运算符: 对于引用类型变量,== 比较的是两个引用变量是否指向同一个对象 (内存地址是否相同)
  • equals() 方法: equals() 方法是 Object 类中定义的方法,子类可以重写它来定义对象内容相等的判断标准。 默认情况下,equals() 方法的行为与 == 相同 (比较引用)。 但很多类 (如 String, Integer, Date 等) 都重写了 equals() 方法,使其比较对象的内容是否相等。

示例:

String str1 = new String("Hello");
String str2 = new String("Hello");
String str3 = str1;

System.out.println(str1 == str2); // 输出: false (str1 和 str2 指向不同的 String 对象,即使内容相同)
System.out.println(str1 == str3); // 输出: true (str1 和 str3 指向同一个 String 对象)
System.out.println(str1.equals(str2)); // 输出: true (String 类的 equals() 方法比较的是字符串内容)

垃圾回收 (Garbage Collection):

  • 当一个对象不再被任何引用变量指向时 (或者说,变得 "不可达" 时),JVM 的垃圾回收器会定期回收这些对象所占用的内存空间。
  • 垃圾回收器会自动管理堆内存,程序员不需要手动释放对象占用的内存 (像 C++ 中那样)。这大大简化了内存管理,并减少了内存泄漏的风险。

Java 常量

常量在程序运行时是不能被修改的。

在 Java 中使用 final 关键字来修饰常量,声明方式和变量类似:

final double PI = 3.1415927;

自动类型转换

整型、实型(常量)、字符型数据可以混合运算。运算中,不同类型的数据先转化为同一类型,然后进行运算。

低 ————————————> 高

byte,short,char—> int —> long—> float —> double

数据类型转换必须满足如下规则:

    1. 不能对boolean类型进行类型转换。
    1. 不能把对象类型转换成不相关类的对象。
    1. 在把容量大的类型转换为容量小的类型时必须使用强制类型转换。
    1. 转换过程中可能导致溢出或损失精度
    2. 浮点数到整数的转换是通过舍弃小数得到,而不是四舍五入

4.JAVA变量

局部变量(Local Variables):局部变量是在方法、构造函数或块内部声明的变量,它们在声明的方法、构造函数或块执行结束后被销毁,局部变量在声明时需要初始化,否则会导致编译错误。

实例变量(Instance Variables):实例变量是在类中声明,但在方法、构造函数或块之外,它们属于类的实例,每个类的实例都有自己的副本,如果不明确初始化,实例变量会被赋予默认值(数值类型为0,boolean类型为false,对象引用类型为null)。

静态变量或类变量(Class Variables):类变量是在类中用 static 关键字声明的变量,它们属于类而不是实例,所有该类的实例共享同一个类变量的值,类变量在类加载时被初始化,而且只初始化一次

public class ExampleClass {
    static int classVar; // 类变量
}

参数变量(Parameters):参数是方法或构造函数声明中的变量,用于接收调用该方法或构造函数时传递的值,参数变量的作用域只限于方法内部

方法参数变量的值传递方式有两种:值传递引用传递

  • 值传递:在方法调用时,传递的是实际参数的值的副本。当参数变量被赋予新的值时,只会修改副本的值,不会影响原始值。Java 中的基本数据类型都采用值传递方式传递参数变量的值。
  • 引用传递:在方法调用时,传递的是实际参数的引用(即内存地址)。当参数变量被赋予新的值时,会修改原始值的内容。Java 中的对象类型采用引用传递方式传递参数变量的值。

Java 的参数传递机制核心理解: 始终是 “按值传递”

  • 对于基本类型参数: 当你将基本类型变量作为参数传递给方法时,方法接收到的是该变量值的副本。 在方法内部对参数的任何修改,都只作用于这个副本,而不会影响到原始变量的值
  • 对于引用类型参数: 当您将引用类型变量(例如,一个对象引用)作为参数传递给方法时,方法接收到的是该引用变量值的副本关键在于,这个副本仍然指向与原始引用变量相同的对象。
    • 这意味着,在方法内部,你可以通过这个引用副本来修改对象的内容 (状态)。 这些修改会反映到原始引用变量所指向的同一个对象上。 因此,看起来像是通过“引用”修改了外部的对象。
    • 但是,如果你在方法内部改变引用变量副本的指向 (例如,让它指向一个新的对象,或者赋值为 null),这只会改变副本的指向,而不会影响到原始引用变量的指向。原始引用变量仍然指向最初的对象(除非它本身就是 null,或者在方法外部被重新赋值)。

5.JAVA修饰符

Java语言提供了很多修饰符,主要分为以下两类:

  • 访问修饰符
  • 非访问修饰符

修饰符用来定义类、方法或者变量,通常放在语句的最前端

访问控制修饰符

Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。

  • default (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
  • private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
  • public : 对所有类可见。使用对象:类、接口、变量、方法
  • protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)

默认访问修饰符-不使用任何关键字

如果在类、变量、方法或构造函数的定义中没有指定任何访问修饰符,那么它们就默认具有默认访问修饰符。

默认访问修饰符的访问级别是包级别(package-level),即只能被同一包中的其他类访问。

如下例所示,变量和方法的声明可以不使用任何修饰符

方法继承的规则:

  • 父类中声明为 public 的方法在子类中也必须为 public。
  • 父类中声明为 protected 的方法在子类中要么声明为 protected,要么声明为 public,不能声明为 private。
  • 父类中声明为 private 的方法,不能够被子类继承。

abstract 修饰符

抽象类:

抽象类不能用来实例化对象,声明抽象类的唯一目的是为了将来对该类进行扩充。

一个类不能同时被 abstract 和 final 修饰。如果一个类包含抽象方法,那么该类一定要声明为抽象类,否则将出现编译错误。

抽象类可以包含抽象方法和非抽象方法。

抽象方法

抽象方法是一种没有任何实现的方法,该方法的具体实现由子类提供。

抽象方法不能被声明成 final 和 static。

任何继承抽象类的子类必须实现父类的所有抽象方法,除非该子类也是抽象类。

如果一个类包含若干个抽象方法,那么该类必须声明为抽象类。抽象类可以不包含抽象方法。

synchronized 修饰符

synchronized 关键字声明的方法同一时间只能被一个线程访问。synchronized 修饰符可以应用于四个访问修饰符。

volatile 修饰符

volatile 修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值。而且,当成员变量发生变化时,会强制线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。

一个 volatile 对象引用可能是 null。

6.基础类型的包装

在实际开发过程中,我们经常会遇到需要使用对象,而不是内置数据类型的情形。为了解决这个问题,Java 语言为每一个内置数据类型提供了对应的包装类。

包装类 基本数据类型
Boolean boolean
Byte byte
Short short
Integer int
Long long
Character char
Float float
Double double

7.String

创建字符串

String str = "Runoob";

String s1 = "Runoob";              // String 直接创建
String s2 = "Runoob";              // String 直接创建
String s3 = s1;                    // 相同引用
String s4 = new String("Runoob");   // String 对象创建
String s5 = new String("Runoob");   // String 对象创建
char[] helloArray = { 'r', 'u', 'n', 'o', 'o', 'b'};
String helloString = new String(helloArray);  
System.out.println( helloString );

创建格式化字符串

String 类使用静态方法 format() 返回一个String 对象

String 类的静态方法 format() 能用来创建可复用的格式化字符串

String fs;
fs = String.format("浮点型变量的值为 " +
                   "%f, 整型变量的值为 " +
                   " %d, 字符串变量的值为 " +
                   " %s", floatVar, intVar, stringVar);
public class Main {
    public static void main(String[] args) {
        String s1 = "hello";
        String s2 = "hello";
        System.out.println(s1 == s2);
        System.out.println(s1.equals(s2));
    }
}

从表面上看,两个字符串用==equals()比较都为true,但实际上那只是Java编译器在编译期,会自动把所有相同的字符串当作一个对象放入常量池,自然s1s2的引用就是相同的。

8.StringBuffer 和 StringBuilder

当对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder 类。

和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象

在使用 StringBuffer 类时,每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,所以如果需要对字符串进行修改推荐使用 StringBuffer。

StringBuilder 类在 Java 5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。

由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。

public class RunoobTest{
    public static void main(String[] args){
        StringBuilder sb = new StringBuilder(10);
        sb.append("Runoob..");
        System.out.println(sb);  
        sb.append("!");
        System.out.println(sb); 
        sb.insert(8, "Java");
        System.out.println(sb); 
        sb.delete(5,8);
        System.out.println(sb);  
    }
}

在Java中,有很多class的定义都符合这样的规范:

  • 若干private实例字段;
  • 通过public方法来读写实例字段。

JavaBean主要用来传递数据,即把一组数据组合成一个JavaBean便于传输。此外,JavaBean可以方便地被IDE工具分析,生成读写属性的代码,主要用在图形界面的可视化设计中。

通过IDE,可以快速生成gettersetter。例如,在Eclipse中,先输入以下代码:

public class Person {
    private String name;
    private int age;
}

然后,点击右键,在弹出的菜单中选择“Source”,“Generate Getters and Setters”,在弹出的对话框中选中需要生成gettersetter方法的字段,点击确定即可由IDE自动完成所有方法代码。

JavaBean是一种符合命名规范的class,它通过gettersetter来定义属性;

属性是一种通用的叫法,并非Java语法规定;

可以利用IDE快速生成gettersetter

使用Introspector.getBeanInfo()可以获取属性列表。