反射机制学习笔记(尚硅谷康师傅2023)(二)

简介: 反射机制学习笔记(尚硅谷康师傅2023)(二)

反射的应用

  • 自定义注解
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String value();
}
  • 自定义接口
public interface MyInterface {
    void method();
}
  • 自定义带泛型的类
public class Creature<T> {
    boolean gender;
    public int id;
    public void breath(){
        System.out.println("呼吸");
    }
    private void info(){
        System.out.println("我是一个生物");
    }
}
  • Person 类
@MyAnnotation("t_persons")
public class Person extends Creature<String> implements Comparable<Person>,MyInterface{
    private String name;
    public int age = 1;
    @MyAnnotation("info")
    private static String info;
    public Person(){
        System.out.println("Person()...");
    }
    protected Person(int age){
        this.age = age;
    }
    private Person(String name, int age){
        this.name = name;
        this.age = age;
    }
    public void show() throws RuntimeException,ClassNotFoundException{
        System.out.println("你好,我是一个Person");
    }
    @MyAnnotation(value="show_nation")
    private String showNation(String nation,int age){
        System.out.println("showNation...");
        return "我的国籍是:" + nation + ",生活了" + age + "年";
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    @Override
    public int compareTo(Person o) {
        return 0;
    }
    @Override
    public void method() {
    }
    public static void showInfo(){
        System.out.println("我是一个人");
    }
}

创建运行时类的对象

  • 利用反射创建 Person 类的对象
  • 通过 Class 实例对象调用 newInstance() 方法即可
  • 运行时类中必须提供一个空参构造器
  • 并且空参构造器的权限必须足够
  • newInstance() 方法,由于使用该方法的要求较高,所以在JDK9开始不被推荐使用,推荐使用Class实例对象.getDeclaredConstructor().newInstance()
  • getDeclaredConstructor() 得到公开的构造器,使用得到的构造器进行对象的创建
// InstantiationException 没有空参构造器会抛出该异常
// IllegalAccessException 空参的构造器权限不足会抛出该异常
@org.junit.Test
public void test01() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
    // 加载类到内存,获取 Person 类对应的运行时类对象
    Class<?> personClass = Class.forName("study02.data.Person");
    // 创建 Person 类的实例对象
    Person person = (Person) personClass.newInstance();
    System.out.println(person);
}

JavaBean 应当提供一个公共的空参构造器

  • 子类对象在实例化时,子类的构造器的首行默认调用父类空参的构造器。
  • 在反射中,经常用来创建运行时类的对象。那么我们要求各个运行时类都提供一个空参的构造器,便于我们编写通用的创建运行时类对象的代码。

获取运行时类的属性

getFields()

  • 获取运行时类及其父类中声明为public访问权限的属性。
@org.junit.Test
public void test1() {
    Class personClass = Person.class;
    // 使用getFields()获取运行时类及其父类中声明为public访问权限的属性。
    // 返回值为一个Field类型的数组
    Field[] fields = personClass.getFields();
    for (Field field : fields) {
        System.out.println(field);
    }
}

getDeclaredField()

  • 获取运行时类中声明的所有属性,不包含父类中声明的属性。
@Test
    public void test2() {
        Class personClass = Person.class;
//        getDeclaredField()获取运行时类中声明的所有属性,不包含父类中声明的属性。
//        返回值为一个Field类型的数组
        Field[] fields = personClass.getDeclaredFields();
        for (Field field: fields) {
            System.out.println(field);
        }
    }

获取属性的结构

  • 属性的权限修饰符、数据类型、变量名等也可以通过反射进行获取。

field.getModifiers()

  • 获取属性的权限修饰符
  • 得到的为权限修饰符对应的数字,默认权限为0
  • 可以使用Modifier.toString(modifiers)将权限修饰符对应数字转换为对应的权限修饰符字符串

field.getType()

  • 获取属性的数据类型
  • 返回值类型为Class
  • type.getName()会返回数据类型的全类名

field.getName()

  • 获取属性的变量名
@Test
    public void test3() {
        Class personClass = Person.class;
        Field[] fields = personClass.getDeclaredFields();
        for (Field field: fields) {
           // 1. 获取属性的权限修饰符
           // field.getModifiers()得到的为权限修饰符对应的数字
           // 默认权限为0
           // 可以使用Modifier.toString(modifiers)将权限修饰符对应数字转换为对应的权限修饰符字符串
            int modifiers = field.getModifiers();
            System.out.println(Modifier.toString(modifiers));
           // 2. 获取属性的数据类型
           // 返回值类型为Class
            Class type = field.getType();
           // type.getName()会返回数据类型的全类名
            System.out.println(type.getName());
           // 3. 获取属性的变量名
            String fieldName = field.getName();
            System.out.println(fieldName);
            System.out.println("---------------");
        }
    }

权限修饰符对应的数字转换为字符串的对应关系

// 对于权限修饰符,将其数字转换为对应的字符串的对应关系
// 0x是十六进制
// * PUBLIC           = 0x00000001;  1  1
// * PRIVATE          = 0x00000002;  2  10
// * PROTECTED        = 0x00000004;  4  100
// * STATIC           = 0x00000008;  8  1000
// * FINAL            = 0x00000010;  16 10000
public static String toString(int mod) {
    StringJoiner sj = new StringJoiner(" ");
    if ((mod & PUBLIC) != 0)        sj.add("public");
    if ((mod & PROTECTED) != 0)     sj.add("protected");
    if ((mod & PRIVATE) != 0)       sj.add("private");
    /* Canonical order */
    if ((mod & ABSTRACT) != 0)      sj.add("abstract");
    if ((mod & STATIC) != 0)        sj.add("static");
    if ((mod & FINAL) != 0)         sj.add("final");
    if ((mod & TRANSIENT) != 0)     sj.add("transient");
    if ((mod & VOLATILE) != 0)      sj.add("volatile");
    if ((mod & SYNCHRONIZED) != 0)  sj.add("synchronized");
    if ((mod & NATIVE) != 0)        sj.add("native");
    if ((mod & STRICT) != 0)        sj.add("strictfp");
    if ((mod & INTERFACE) != 0)     sj.add("interface");
    return sj.toString();
}

获取运行时类的方法

getMethods()

  • 获取运行时类及其所有父类中声明为public访问权限的方法。
@Test
    public void test1() {
        Class personClass = Person.class;
       // getMethods()获取运行时类及其所有父类中声明为public访问权限的方法。
       // 返回值为Method类型的数组
        Method[] methods = personClass.getMethods();
        for (Method method: methods) {
            System.out.println(method);
        }
    }

getDeclaredMethods()

  • 获取运行时类中声明的所有方法,不包含父类中声明的方法
@Test
    public void test2() {
        Class personClass = Person.class;
       // getDeclaredMethods()获取运行时类中声明的所有方法,不包含父类中声明的方法
       // 返回值为Method类型的数组
        Method[] methods = personClass.getDeclaredMethods();
        for (Method method: methods) {
            System.out.println(method);
        }
    }

获取方法的结构

  • 方法的结构:
@Xxxx
权限修饰符 返回值类型 方法名(参数类型1 参数名1, ...) throws Exception {}

method.getAnnotations()

  • 获取方法声明的注解
  • 返回值为Annotation类型的数组,因为一个方法上可以加多个注解

method.getModifiers()

  • 得到的为权限修饰符对应的数字
  • Modifier.toString()将权限修饰符数字转换为对应的字符串

method.getReturnType()

  • 获取方法的返回值类型
  • type.getName() 获取返回值类型对应的字符串

method.getName()

  • 获取方法的方法名

method.getParameterTypes()

  • 获取方法的形参列表
  • 返回 Class 类型的数组

method.getExceptionTypes()

  • 获取方法抛出的异常
  • 返回 Class 类型的数组,因为抛出的异常可能有多个也可能没有异常的抛出
@Test
    public void test4() {
        Class clazz = Person.class;
        Method[] methods = clazz.getDeclaredMethods();
        for (Method m : methods) {
            //1.获取方法声明的注解
            //返回值为Annotation类型的数组,因为一个方法上可以加多个注解
            Annotation[] annos = m.getAnnotations();
            for (Annotation a : annos) {
                System.out.println(a);
            }
            //2.权限修饰符
            //m.getModifiers()得到的为权限修饰符对应的数字
            //Modifier.toString()将权限修饰符数字转换为对应的字符串
            System.out.print(Modifier.toString(m.getModifiers()) + "\t");
            //3.返回值类型
            System.out.print(m.getReturnType().getName() + "\t");
            //4.方法名
            System.out.print(m.getName());
            System.out.print("(");
            //5.形参列表
            Class[] parameterTypes = m.getParameterTypes();
            //判断方法是否有形参列表
            if (!(parameterTypes == null || parameterTypes.length == 0)) {
                // 循环输出参数类型
                for (int i = 0; i < parameterTypes.length; i++) {
                    // 最后一个形参的输出进行特殊处理
                    if (i == parameterTypes.length - 1) {
                        System.out.print(parameterTypes[i].getName() + " args_" + i);
                        break;
                    }
                    System.out.print(parameterTypes[i].getName() + " args_" + i + ",");
                }
            }
            System.out.print(")");
            //6.抛出的异常
            //抛出的异常可能有多个也可能没有异常的抛出
            Class[] exceptionTypes = m.getExceptionTypes();
            //判断是否有异常的抛出
            if (exceptionTypes.length > 0) {
                System.out.print("throws ");
                for (int i = 0; i < exceptionTypes.length; i++) {
                    if (i == exceptionTypes.length - 1) {
                        System.out.print(exceptionTypes[i].getName());
                        break;
                    }
                    System.out.print(exceptionTypes[i].getName() + ",");
                }
            }
            System.out.println("{}");
        }
    }

获取运行时类的构造器

getConstructors()

  • 获取运行时类中声明为public访问权限的构造器。
@Test
public void test1() {
    Class personClass = Person.class;
   // getConstructors()获取运行时类中声明为public访问权限的构造器。
   // 返回值为Constructor类型的数组,构造器可能有多个
    Constructor[] constructors = personClass.getConstructors();
    for (Constructor constructor : constructors) {
        System.out.println(constructor);
    }
}

getDeclaredConstructors()

  • 获取运行时类中声明的所有构造器
@Test
public void test2() {
    Class personClass = Person.class;
   // getDeclaredConstructors()获取运行时类中声明的所有构造器
   // 返回值为Constructor类型的数组,构造器可能有多个
    Constructor[] constructors = personClass.getDeclaredConstructors();
    for (Constructor constructor : constructors) {
        System.out.println(constructor);
    }
}

  • 通过反射也可以获取构造器的结构,获取方法与获取方法的结构类似。

获取运行时类的父类

@Test
public void test() {
    Class personClass = Person.class;
   // 获取运行时类的父类
   // 运行时类的父类的类型也为Class
    Class superClass = personClass.getSuperclass();
    System.out.println(superClass);
}

获取运行时类的带泛型的父类

@Test
public void test() {
    Class personClass = Person.class;
    // 获取运行时类的带泛型的父类
    Type genericSuperclass = personClass.getGenericSuperclass();
    System.out.println(genericSuperclass);
}

获取运行时类的带泛型的父类的泛型

@Test
public void test() {
    Class personClass = Person.class;
    // 先获取带泛型的父类
    // Type 是一个接口,Class 实现了该接口
    Type genericSuperclass = personClass.getGenericSuperclass();
    System.out.println(genericSuperclass);
    // 已经确定genericSuperclass带有泛型,将其强转为带有参数类型ParameterizedType类型
    ParameterizedType paramType = (ParameterizedType) genericSuperclass;
    //调用getActualTypeArguments()获取泛型
    //返回的为数组,是由于有时候泛型有多个,如Map<K, V>就有两个泛型
    Type[] actualTypeArguments = paramType.getActualTypeArguments();
    System.out.println(actualTypeArguments[0].getTypeName());
}

获取运行时类实现的接口

获取运行时类实现的接口

@Test
public void test() {
    Class clazz = Person.class;
    // 获取运行时类实现的接口
    // 由于实现的接口可能有多个,所以返回的为数组
    Class[] interfaces = clazz.getInterfaces();
    for(Class c : interfaces){
        System.out.println(c);
    }
}

获取运行时类的父类实现的接口

@Test
public void test() {
    Class clazz = Person.class;
    //获取运行时类的父类实现的接口
    //先获取运行时类的父类
    //然后获取运行时类的父类实现的接口
    Class[] interfaces1 = clazz.getSuperclass().getInterfaces();
    for(Class c : interfaces1){
        System.out.println(c);
    }
}

获取运行时类所在的包

@Test
public void test() {
    Class clazz = Person.class;
    Package pack = clazz.getPackage();
    System.out.println(pack);
}

获取运行时类的注解

  • JDK 5.0 在 java.lang.reflect 包下新增了 AnnotatedElement 接口, 该接口代表程序中可以接受注解的程序元素。当一个 Annotation 类型被定义为运行时 Annotation 后, 该注解才是运行时可见,当 class 文件被载入时保存在 class 文件中的 Annotation 才会被虚拟机读取,程序可以调用 AnnotatedElement对象的如下方法来访问 Annotation 信息:
@Test
    public void test() {
        Class clazz = Person.class;
        Annotation[] annotations = clazz.getAnnotations();
        for(Annotation annos : annotations){
            System.out.println(annos);
        }
    }

调用指定的属性

  • 调用指定属性的步骤:
  • 步骤1:通过Class实例调用getDeclaredField(String fieldName),获取运行时类指定名的属性
  • 步骤2:setAccessible(true):确保此属性是可以访问的
  • 步骤3:通过Filed类的实例调用get(Object obj) (获取的操作)或 set(Object obj,Object value) (设置的操作)进行操作。
@org.junit.Test
public void test03() throws Exception {
    // 加载类,获取该类对应的Class实例
    Class<?> personClass = Class.forName("study02.data.Person");
    // 创建对象
    Person person = (Person) personClass.getDeclaredConstructor().newInstance();
    /*
     * 公共的非静态的属性
     */
    // 获取运行时类的指定名的属性
    Field age = personClass.getField("age"); // 该属性公共的非静态的
    // 获取属性值
    // 由于是非静态的,所以要指明获取哪个对象的属性
    Object personAge = age.get(person); // 返回的为该对象的属性值
    System.out.println("person age 属性的初始值为:" + personAge);
    // 设置属性值
    age.set(person, 22); // 设置person的age属性的属性值为22
    System.out.println("person age 属性的当前值为:" + age.get(person));
    /*
     * 私有的属性(获取当前运行时类的公共属性或私有属性都可以采用下面的方法)
     */
    // getField() 获取运行时类及其父类中声明为 public 访问权限的属性
    // 获取私有属性需要使用 getDeclaredField() 获取运行时类中声明的所有属性,不包含父类中声明的属性
    Field name = personClass.getDeclaredField("name");
    // 私有权限默认不能进行访问
    // 要访问私有权限,需要修改其是否可以访问 确保属性可以访问
    name.setAccessible(true); // 修改为可以进行访问
    name.set(person, "张三"); // 设置person的name为 “张三”
    String personName = (String) name.get(person); // 获取person的name
    System.out.println("person 的 name 为:" + personName);
  /*
     * 运行时类的静态属性
     */
    Field info = personClass.getDeclaredField("info"); // 获取属性
    info.setAccessible(true); // 设置为可以访问
  // 对应静态变量,info.set(null, "Person 类的信息..."); 也是可以的
  // 因为获取 静态属性 时已经知道该属性是哪个类的了,无向再次指明
    info.set(personClass, "Person 类的信息..."); // 由于是静态属性所以调用该方法的对象为类对应的Class实例
    // info.get(null)
  Object PersonInfo = info.get(personClass); // 获取属性值
    System.out.println(PersonInfo);
}

调用指定的方法

  • 调用指定方法的步骤:
  • 步骤1.通过Class的实例调用getDeclaredMethod(String methodName,Class … args),获取指定的方法
  • 步骤2. setAccessible(true):确保此方法是可访问的
  • 步骤3.通过Method实例调用invoke(Object obj,Object … objs),即为对Method对应的方法的调用。
  • invoke()的返回值即为Method对应的方法的返回值
  • 特别的:如果Method对应的方法的返回值类型为void,则invoke()返回值为null
@org.junit.Test
public void test04() throws Exception {
    // 获取运行时类Class对象
    Class<Person> personClass = Person.class;
    // 创建Person对象
    Person person = personClass.getDeclaredConstructor().newInstance();
    // 获取方法 private String showNation(String nation,int age) {}
    // 参数一:方法名
    // 参数二:可变形参,方法的形参列表中的各参数的类型(参数类型要对应)
    // 类型不能自动装箱,类型的值才可以自动装箱
    Method showNation = personClass.getDeclaredMethod("showNation", String.class, int.class);
    // 设置方法是否可以访问
    showNation.setAccessible(true);
    // 参数一:调用哪个对象的该方法
    // 参数二:可变形参,方法的形参
    // 返回值为方法的返回值
    Object invokeBack = showNation.invoke(person, "中国", 23);
    System.out.println(invokeBack);
}

调用指定的构造器

  • 调用指定构造器的步骤:
  • 步骤1.通过Class的实例调用getDeclaredConstructor(Class … args),获取指定参数类型的构造器
  • 步骤2.setAccessible(true):确保此构造器是可以访问的
  • 步骤3.通过Constructor实例调用newInstance(Object … objs),返回一个运行时类的实例。
@org.junit.Test
public void test05() throws Exception {
    // 获取运行时类
    Class<Person> personClass = Person.class;
    // 获取构造器 private Person(String name, int age) {}
    // 参数:可变形参,构造器形参的类型
    Constructor<Person> personConstructor = personClass.getDeclaredConstructor(String.class, int.class);
    // 设置构造器可以进行访问
    personConstructor.setAccessible(true);
    // 利用获取的构造器创建对象
    Person person = personConstructor.newInstance("张三", 34);
    System.out.println(person);
}

获取指定的注解

自定义注解

/**
 * ClassName: Table
 * Package: PACKAGE_NAME
 * Description:
 * 普通Java对象和数据库中哪个表对应
 *
 * @Author tcw
 * @Create 2023-05-25 9:25
 * @Version 1.0
 */
@Target(ElementType.TYPE) // 该注解只能使用在类、接口、枚举、记录上
@Retention(RetentionPolicy.RUNTIME) // 在运行时需要可以通过反射获取该注解,所以RUNTIME
public @interface Table {
    String value();
}
/**
 * ClassName: Column
 * Package: PACKAGE_NAME
 * Description:
 *
 * @Author tcw
 * @Create 2023-05-25 9:32
 * @Version 1.0
 */
@Target(ElementType.FIELD) // 该注解只能在属性上
@Retention(RetentionPolicy.RUNTIME) // 在运行时需要可以通过反射获取该注解,所以RUNTIME
public @interface Column {
    String columnName(); // 对应数据库表中字段的字段名
    String columnType(); // 对应数据库表中字段的字段类型
}

Java 类

/**
 * ClassName: Customer
 * Package: PACKAGE_NAME
 * Description:
 *
 * @Author tcw
 * @Create 2023-05-25 9:29
 * @Version 1.0
 */
@Table("t_customer") // 该Java类与数据库中的t_customer表对应
public class Customer {
    @Column(columnName = "name", columnType = "varchar(10)")
    private String name;
    @Column(columnName = "age", columnType = "int")
    private Integer age;
    public Customer() {
    }
    public Customer(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Customer{" + "name='" + name + '\'' + ", age=" + age + '}';
    }
}

获取注解

@Test
public void test() throws Exception {
    // 加载类获取类对应的Class实例
    Class<?> customer = Class.forName("Customer");
    // 获取类上的注解(Table)
    Table customerDeclaredAnnotation = customer.getDeclaredAnnotation(Table.class);
    // 获取注解的属性
    System.out.println("该Java类对应的数据库表为:" + customerDeclaredAnnotation.value());
    // 获取属性
    Field[] customerDeclaredFields = customer.getDeclaredFields();
    // 获取属性上的注解
    for (Field customerDeclaredField : customerDeclaredFields) {
        Column fieldAnnotation = customerDeclaredField.getAnnotation(Column.class);
        System.out.print("对应数据库中的字段:" + fieldAnnotation.columnName());
        System.out.println(" 类型为:" + fieldAnnotation.columnType());
    }
}

反射练习

案例:榨汁机榨水果汁,水果分别有苹果(Apple)、香蕉(Banana)、桔子(Orange)等。

提示:

1、声明(Fruit)水果接口,包含榨汁抽象方法:void squeeze(); /skwiːz/

2、声明榨汁机(Juicer),包含运行方法:public void run(Fruit f),方法体中,调用f的榨汁方法squeeze()

3、声明各种水果类,实现水果接口,并重写squeeze();

4、在src下,建立配置文件:config.properties,并在配置文件中配上fruitName=xxx(其中xx为某种水果的全类名)

5、在FruitTest测试类中,

(1)读取配置文件,获取水果类名,并用反射创建水果对象,

(2)创建榨汁机对象,并调用run()方法

接口声明

/**
 * ClassName: Fruit
 * Package: PACKAGE_NAME
 * Description:
 *
 * @Author tcw
 * @Create 2023-05-25 10:07
 * @Version 1.0
 */
public interface Fruit {
    /**
     * 水果榨汁的方法
     */
    void squeeze();
}

水果类

/**
 * ClassName: Apple
 * Package: PACKAGE_NAME
 * Description:
 *
 * @Author tcw
 * @Create 2023-05-25 10:09
 * @Version 1.0
 */
public class Apple implements Fruit{
    @Override
    public void squeeze() {
        System.out.println("苹果汁...");
    }
}
public class Banana implements Fruit{
    @Override
    public void squeeze() {
        System.out.println("香蕉汁....");
    }
}
public class Orange implements Fruit{
    @Override
    public void squeeze() {
        System.out.println("橘子汁...");
    }
}

榨汁机类

public class Juicer {
    /**
     * 使用需要进行榨汁的水果榨汁
     * 
     * @param fruit 水果
     */ 
    public static void run(Fruit fruit) {
        fruit.squeeze(); // 榨汁
    }
}

配置文件

fruitName=Apple

测试

/**
 * ClassName: FruitTest
 * Package: PACKAGE_NAME
 * Description:
 *
 * @Author tcw
 * @Create 2023-05-25 10:14
 * @Version 1.0
 */
public class FruitTest {
    public static void main(String[] args) throws Exception {
        // 利用类加载器加载配置文件
        ClassLoader classLoader = FruitTest.class.getClassLoader();
        InputStream resource = classLoader.getResourceAsStream("config.properties"); // 默认从src下开始查找文件
        // 使用Properties对象加载文件中的内容
        Properties properties = new Properties();
        properties.load(resource);
        // 获取需要进行榨汁的水果(获取全类名)
        String fruitName = (String) properties.get("fruitName");
        // 利用反射创建相应水果的实例对象
        Class<?> fruitClass = Class.forName(fruitName); // 加载类
        Fruit fruit = (Fruit) fruitClass.getDeclaredConstructor().newInstance(); // 虽然不知道是什么水果但是一定是水果
        // 调用榨汁机榨汁方法进行榨汁
        Juicer.run(fruit);
    }
}


相关文章
|
7月前
|
前端开发 JavaScript 算法
尚硅谷JVM全套教程
尚硅谷JVM全套教程
|
存储 安全 Java
2023年Java核心技术第九篇(篇篇万字精讲)(下)
2023年Java核心技术第九篇(篇篇万字精讲)(下)
65 0
|
缓存 安全 Java
2023年Java核心技术第九篇(篇篇万字精讲)(上)
2023年Java核心技术第九篇(篇篇万字精讲)(上)
47 0
|
4月前
|
前端开发 JavaScript 程序员
成功解决:尚硅谷中的谷粒商城前端项目运行依赖问题。【详细图解+问题说明+解决思路】
这篇文章介绍了如何解决尚硅谷谷粒商城前端项目中遇到的依赖问题,通过修改`package.json`和`package-lock.json`中的`node-sass`和`sass-loader`版本,成功解决了node版本与这些依赖的兼容性问题。
成功解决:尚硅谷中的谷粒商城前端项目运行依赖问题。【详细图解+问题说明+解决思路】
|
6月前
|
数据库 云计算 Python
不容错过的经典!Python核心编程(第3版)教你用实例学Python!
在学完任何其他入门类的 Python 图书之后,你可能觉得已经掌握了 Python 而且还觉得学得不错,并为此感到自豪。通过完成大量练习之后,你将会对自己新掌握的 Python 编程技能拥有更多信心。 但是,你可能仍然会有这样的疑问,“现在该怎么办?我能用 Python 编写哪种类型的应用程序呢?”或许你是为了一个相当小众的工作项目而学习使用 Python,你可能会考虑“我还能用 Python 写点其他的吗?”
|
5月前
|
存储 Python
逆天改命?Python元类:从菜鸟到大师,一键升级你的编程认知
【7月更文挑战第6天】Python的元类是类的构造器,允许控制类的创建。元类`Meta`通过`__new__`方法动态添加属性,如示例所示,创建`MyClass`时添加`new_attr`。元类还能实现高级功能,如单例模式,`SingletonMeta`元类确保同一类的所有实例相等。元类是进阶技术,能提升代码的灵活性和创造力。
40 0
|
6月前
|
JavaScript 前端开发 程序员
技术心得记录:学习尚硅谷张天禹老师的VUE2基础部分教程笔记
技术心得记录:学习尚硅谷张天禹老师的VUE2基础部分教程笔记
134 0
|
XML SQL JSON
JDK14(Java14) 新特性学习笔记(尚硅谷宋红康康师傅2020)
JDK14(Java14) 新特性学习笔记(尚硅谷宋红康康师傅2020)
|
缓存 前端开发 JavaScript
反射机制学习笔记(尚硅谷康师傅2023)(一)
反射机制学习笔记(尚硅谷康师傅2023)(一)
|
存储 Java 程序员
一起啃书(C Primer Plus 第六版)--数据和C<附大量编程题>
一起啃书(C Primer Plus 第六版)--数据和C<附大量编程题>
150 0