博文正文开头格式:(2分)

项目

内容

《面向对象程序设计(java)》

https://www.cnblogs.com/nwnu-daizh/

这个作业的要求在哪里

https://www.cnblogs.com/nwnu-daizh/p/11552848.html

作业学习目标

  1. 掌握类与对象的基础概念,理解类与对象的关系;
  2. 掌握对象与对象变量的关系;
  3. 掌握预定义类Date、LocalDate类的常用API;
  4. 掌握用户自定义类的语法规则,包括实例域、静态域、构造器方法、更改器方法、访问器方法、静态方法、main方法、方法参数的定义要求;(重点、难点)
  5. 掌握对象的构造方法、定义方法及使用要求;(重点);
  6. 理解重载概念及用法;
  7. 掌握包的概念及用法;

随笔博文正文内容包括:

第一部分:总结第四章理论知识(20分)

面向对象程序程序设计概述: 面向对象程序程序设计(OOP)是当今主流的程序设计范型;面向对象的程序是由对象组成的,每个对象包含对用户公开的特定功能部分和隐藏的实现部分,程序中的很多对象来自标准库,还有一些自定义的,一般会提供类、封装、继承等语法和概念来辅助我们进行面向对象编程。在面向过程程序设计中,数据和对数据的操作是分离的,因而这种做法需要把数据传递到过程和函数中;而面向对象程序设计把数据和属于它们的操作放入同一个数据结构,数据和操作都在同一个统一体内,所以解决了面向过程程序设计不可避免的很多问题。 所谓的面向对象就是将我们的程序模块化,对象化,把具体事物的特性属性和通过这些属性来实现一些动作的具体方法放到一个类里面。

1.面向对象的三大特性为封装、继承、多态。

封装:是将数据和行为组合在一个包中,并对对象的使用者隐藏了数据的实现方式,实现封装的关键在于不能让类中的方法直接访问其他类的实例域。

对象中的数据称为实例域,操纵数据的过程称为方法,对于每个特定的类实例都有一组特定的实例域值,这些值的集合就是这个对象的当前状态。

继承:通过扩展一个类来建立另外一个类的过程,在Java中所有的类都源自于object。 在扩展一个已有的类时,这个扩展后的新类具有所扩展的类的全部属性和方法。

2.对象的三个特性:对象的行为,对象的状态,对象标识。

类与对象的关系:类是对象的模板,对象是类的实例,类只能通过对象才能使用。

类之间的关系:依赖、聚合、继承。

类的组成:属性、方法,

3.使用预定义类:要想使用对象,必须首先构造对象,并指定其初始状态。构造器是一种特殊的方法,用来构造并初始化对象,构造器的名字应该与类名相同,

对象的产生格式:类名称  对象名称 = new 类名称()。

如果一个对象没有被实例化而直接使用,则使用时会出现空指针异常。

4.Java类库中的LocaiDate(日历表示法)类:一旦有了一个LocalDate对象,可以用方法getYear、getMonthValue、getDayOfMonth得到年、月、日。用plusDays方法得到一个新的LocalDate对象。

5.用户自定义类:Employee类、多个源文件的使用、

从构造器开始:构造器与其他的方法有一个重要的不同,构造器总是伴随着new操作符的执行被调用,而不能对一个已经存在的对象调用构造器来达到重新设置实例域的目的。构造器与类同名,每个类可以有一个以上 的构造器,构造器可以有1个、0个或多个以上的参数,构造器没有返回值,构造器总是伴随着new操作一起调用。

构造方法可以为类中的属性初始化,构造方法与类名称相同,无返回值类型声明,如果在类中没有明确的定义出构造方法,则会生成一个无参的构造方法,在一个类中的构造方法可以重载,但是每个类都至少有一个构造方法。

隐式(implicit)参数与显式(explicit)参数:用于操作对象以及存取它们的实例域,implicit参数出现在方法名前的Employee类对象,explicit参数位于方法名后面括号中的数值,明显列在方法声明中,在每一个方法中,关键字this表示隐式参数,在Java中使用this关键字可以表示当前对象,通过“this.属性”可以调用本类中的属性,通过“this.方法”可以调用本类中其他方法;也可以通过this()的形式调用本类中的构造方法,但是调用时要求放在构造方法的首行。。

封装的优点:可以改变内部实现,除了该类的方法之外,不会影响i其他代码。更改器方法可以执行错误检查,然而直接对域进行赋值将不会进行这些处理。

私有方法:为了实现一个私有方法,只需将关键字public改为private。类的封装性:通过private关键字进行修饰,被传递的属性不能被外部直接调用,而只能通过getter或setter方法完成,只要是属性则必须封装。

6.类属于引用数据类型,进行引用传递时,传递的是堆内存的使用权。

7.final实例域:可以将实例域定义为final,构造对象时必须初始化这样的域,final修饰符大都应用于基本类型域或不可变类的域。final加在数据成员变量前,这样该变量变成一个常量,因此无法在程序代码中再做修改。使用public static final可以声明一个全局常量。

8.静态域与静态方法:

静态域(nextID):静态域杯称为类域。

静态常量:例PI=3.14

静态方法:可以省略关键字static,需要用Employee类对象的引用调用这个方法。

工厂方法、main方法。

9.对象构造:

String类在Java中比较特殊,String可以使用直接复制的方式,也可以通过构造方法进行实例化,前者指产生一个实例化对象,而且此实例化对象可以重用,后者将产生两个实例化对象,其中一个是垃圾空间,在String中比较内容是用equals方法,而“==”比较的是两个字符串的地址值。字符串的内容一旦声明则不可改变。

使用static声明的属性和方法可以由类名称直接调用,static属性是所有对象共享的,对可以对其进行操作。

如果需要限制类对象的产生,则可以将构造方法私有化。

对象数组的使用要分为声明数组和为数组开辟空间两步。开辟空间后数组中的每个元素的内容都是null。

10.包:

类的导入:

内部类是在一个类的内部定义另外一个类,使用内部类可以方便访问外部类的私有操作。在方法中声明的内部类要想访问方法的参数,则参数前必须加上final关键字。

继承可以扩充已有类的功能,通过extends关键字实现,可将父类的成员继承到子类。Java在执行子类的构造方法前会先调用父类中无参的构造方法,其目的是为了继承自父类的成员做初始化操作。父类有多个构造方法时,如要调用特定的构造方法则可在子类的构造方法中通过super()关键字实现。

this()用于在同一类内调用其他构造方法,而super()则用于从子类的构造方法中调用其父类的构造方法。 使用this调用属性和方法时会现在本类中查找,如果本类中没有再从父类中查找,而使用super则会直接从父类中查找需要的属性和方法。this()与super()相似之处在于:当构造方法重载时,两者均会根据所给予的参数类型与个数正确地执行相对应的构造方法;两者均必须编写在构造方法内的第一行,也正是这个原因,this()和super()无法同时存在同一个构造方法中。

重载(overloading)是指在相同类内定义名称相同但参数个数或类型不同的方法,因此,Java可依据参数的个数或类型调用相应的方法。

重写(overriding)是在子类当中定义名称、参数个数与类型均与父类相同的方法,用来覆写父类中的方法。

如果父类的方法不希望被子类覆写,可在父类的方法前加final关键字。

所有的类均继承自Object类。一个好的类应该覆写Object类中的toString()、equals()、hashCode()3个方法,所有的对象都可以向Object类进行向上转型

抽象类不能直接用来产生对象,必须通过对象的多态性进行实例化操作。 抽象类的方法分为两种,一种是一般的方法,另一种是以abstract关键字开头的抽象方法。抽象方法并没有定义方法体,而是要保留给由抽象类派生出的新类来定义。

接口是方法和全局常量的集合,接口必须由子类来实现,一个接口可以同时继承多个接口,一个子类可以同时实现多个接口。

Java不允许类的多重继承,但是允许实现多个接口。

Java对象的多态性分为向上转型(自动)和向下转型(强制)。

通过instanceof关键字可以判断对象属于哪个类。

匿名内部类的作用是可利用内部类创建不具有名称的对象,并利用它访问类中的成员

把类放入包中:

在Java中使用package关键字来将一个类放入一个包中。

在Java中使用import语句可以导入一个已有的包。

Java中的访问控制权限分为4种,即private、default、protected、public。

第二部分:实验部分

实验名称:实验三 类与对象的定义及使用

1.  实验目的:

(1) 熟悉PTA平台线上测试环境;

(2) 理解用户自定义类的定义;

(3) 掌握对象的声明;

(4) 学会使用构造函数初始化对象;

(5) 使用类属性与方法的使用掌握使用;

(6) 掌握package和import语句的用途。

3. 实验步骤与内容:

实验1  任务1(10分)

程序代码如下:

import java.util.Scanner;

public class Shen {

    public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner in = new Scanner(System.in);
System.out.println("please input your ID:");
String s1 = in.nextLine();
String s2,s3,s4;
s2 = s1.substring(6, 10);
s3 =s1.substring(10, 12);
s4 = s1.substring(12, 14);
System.out.println(s2+"-"+s3+"-"+s4); } }

  程序运行结果如下图:

实验1  任务2(25分)

程序代码如下:

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner; public class Main {
// private static Student students[]; private static ArrayList<Student> list; public static void main(String[] args) {
list = new ArrayList<>();
Scanner in = new Scanner(System.in);
try {
readFile("studentfile.txt");
System.out.println("请选择操作,1按姓名,2按学号,3退出");
int i;
while ((i = in.nextInt()) != 3) {
switch (i) {
case 1:
System.out.println("请输入姓名");
String name = in.next();
Student student = findStudentByName(name);
if (student == null) {
System.out.println("没找到");
} else {
System.out.println(student.toString());
}
System.out.println("请选择操作,1按姓名,2按学号,3退出");
break;
case 2:
System.out.println("请输入学号");
String id = in.next();
Student student1 = findStudentById(id);
if (student1 == null) {
System.out.println("没找到");
} else {
System.out.println(student1.toString()); }
System.out.println("请选择操作,1按姓名,2按学号,3退出");
break; default:
System.out.println("输入有误");
System.out.println("请选择操作,1按姓名,2按学号,3退出");
break;
} }
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}finally {
in.close();
} } public static void readFile(String path) throws IOException {
FileReader reader = new FileReader(path);
BufferedReader br = new BufferedReader(reader);
String result;
while ((result = br.readLine()) != null) {
Student student = new Student();
student.setName(result.substring(13));
student.setID(result.substring(0,12));
list.add(student);
}
br.close();
} public static Student findStudentByName(String name) {
for (Student student : list) {
if (student.getName().equals(name)) {
return student;
}
}
return null; } public static Student findStudentById(String Id) {
for (Student student : list) {
if (student.getID().equals(Id)) {
return student;
}
}
return null; }
} class Student {
private String name;
private String ID; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getID() {
return ID;
} public void setID(String iD) {
ID = iD;
} @Override
public String toString() {
// TODO 自动生成的方法存根
return "姓名是:" + name + "学号是:" + ID;
}
}

  运行结果如下图:

实验2  测试程序1(10分)

(1)程序代码如下:

import java.time.*;

/**
* This program tests the Employee class.
* @version 1.13 2018-04-10
* @author Cay Horstmann
*/
public class EmployeeTest
{
public static void main(String[] args)
{
//构造一个Employee数组,并填入三个雇员对象
Employee[] staff = new Employee[3]; staff[0] = new Employee("Carl Cracker", 75000, 1987, 12, 15);
staff[1] = new Employee("Harry Hacker", 50000, 1989, 10, 1);
staff[2] = new Employee("Tony Tester", 40000, 1990, 3, 15); // 用Employee类的raiseSalary方法将每个雇员的薪水提高5%
for (Employee e : staff)
e.raiseSalary(5); // 调用getName方法、getSalary方法和getHireDay方法将每一个雇员的信息打印出来
for (Employee e : staff)
System.out.println("name=" + e.getName() + ",salary=" + e.getSalary() + ",hireDay="
+ e.getHireDay());
}
} class Employee
{
private String name; //实例域定义
private double salary;
private LocalDate hireDay; public Employee(String n, double s, int year, int month, int day) //构造器定义
{
name = n;
salary = s;
hireDay = LocalDate.of(year, month, day);
} public String getName() //实例域name的访问器方法
{
return name;
} public double getSalary() //实例域salary的访问器方法
{
return salary;
} public LocalDate getHireDay() //实例域HireDay的访问器方法
{
return hireDay;
} //调用raiseSalary方法的对象的salary实例域设置为新值
public void raiseSalary(double byPercent)
{
double raise = salary * byPercent / 100;
salary += raise;
}
}

  

  运行结果如下图:

(2)

EmployeeTest.java程序代码如下:

  public class EmployeeTest
{
public static void main(String[] args)
{
// 用三个employee对象填充staff数组
Employee[] staff = new Employee[3]; staff[0] = new Employee("Carl Cracker", 75000, 1987, 12, 15);
staff[1] = new Employee("Harry Hacker", 50000, 1989, 10, 1);
staff[2] = new Employee("Tony Tester", 40000, 1990, 3, 15); // raise everyone's salary by 5% 给每人涨5%的工资
for (Employee e : staff) //进行foreach循环
e.raiseSalary(5); // print out information about all Employee objects
for (Employee e : staff)
System.out.println("name=" + e.getName() + ",salary=" + e.getSalary() + ",hireDay="
+ e.getHireDay());
}
}

  运行结果如下图:

Employee.java程序代码如下:

 import java.time.LocalDate; 

  public class Employee {

   private String name;   //实例域定义
private double salary; //实例域定义
private LocalDate hireDay; //实例域定义 public Employee(String n, double s, int year, int month, int day) //构造器的定义
{
name = n;
salary = s;
hireDay = LocalDate.of(year, month, day);
} public String getName() //实例域name的访问器方法
{
return name;
} public double getSalary() //实例域Salary的访问器方法
{
return salary;
} public LocalDate getHireDay() ////实例域HireDay的访问器方法
{
return hireDay;
} public void raiseSalary(double byPercent)
{
double raise = salary * byPercent / 100;
salary += raise;
}
}

  运行结果如下图:

(3)程序代码如下:

 import java.util.Scanner;

  public class student {
String name;
String sex;
double javascore;
public static void main(String[] args) {
System.out.println("请输入学生人数");
Scanner su = new Scanner(System.in);
int totalStudent = su.nextInt();
student[] stus= new student[totalStudent];
for(int i=0;i<totalStudent;i++) {
student s =new student();
stus[i]=s;
System.out.println("请输入第+“i"+"个学生的姓名");
s.name = su.next();
System.out.println("请输入第+“i"+"个学生的性别");
s.sex = su.next();
System.out.println("请输入第+“i"+"个学生的java成绩");
s.javascore = su.nextDouble(); }
printstudent(stus);
su.close();
} public static void printstudent(student[] s) {
System.out.println("姓名\t性别\tjava成绩");
for(int i=0;i<s.length;i++) {
System.out.println(s[i].name+"\t"+s[i].sex+"\t"+s[i].javascore);
}
}
}

  运行结果如下图:

实验2  测试程序2(5分)

程序代码如下:

/**
* This program demonstrates static methods.
* @version 1.02 2008-04-10
* @author Cay Horstmann
*/
public class StaticTest
{
public static void main(String[] args)
{
// fill the staff array with three Employee objects
var staff = new Employee[3]; //构造了一个Employee 数组,并填入三个雇员对象 staff[0] = new Employee("Tom", 40000);
staff[1] = new Employee("Dick", 60000);
staff[2] = new Employee("Harry", 65000); // print out information about all Employee objects
for (Employee e : staff) //调用getName 方法,getId方法和getSalary方法将每个雇员的信息打印出来
{
e.setId();
System.out.println("name=" + e.getName() + ",id=" + e.getId() + ",salary="
+ e.getSalary());
} int n = Employee.getNextId(); // calls static method
System.out.println("Next available id=" + n);
}
} class Employee
{
private static int nextId = 1; private String name; //实例域定义
private double salary;
private int id; public Employee(String n, double s) //构造器定义
{
name = n;
salary = s;
id = 0;
} public String getName() //实例域name的访问器方法
{
return name;
} public double getSalary() //实例域salary的访问器方法
{
return salary;
} public int getId() //实例域id的访问器方法
{
return id;
} public void setId()
{
id = nextId; // set id to next available id
nextId++;
} public static int getNextId() //实例域NextId的访问方法
{
return nextId; // returns static field
} public static void main(String[] args) // unit test
{
var e = new Employee("Harry", 50000);
System.out.println(e.getName() + " " + e.getSalary());
}
}

  运行结果如下图:

实验2  测试程序3(5分)

程序代码如下:

/**
* This program demonstrates parameter passing in Java.
* @version 1.01 2018-04-10
* @author Cay Horstmann
*/
public class ParamTest
{
public static void main(String[] args)
{
/*
* Test 1: Methods can't modify numeric parameters(方法不能修改数值参数)
*/
System.out.println("Testing tripleValue:");
double percent = 10;
System.out.println("Before: percent=" + percent);
tripleValue(percent); //调用方法tripleSalary
System.out.println("After: percent=" + percent); /*
* Test 2: Methods can change the state of object parameters (方法可以更改对象参数的状态)
*/
System.out.println("\nTesting tripleSalary:");
var harry = new Employee("Harry", 50000);
System.out.println("Before: salary=" + harry.getSalary());
tripleSalary(harry); //调用方法tripleSalary
System.out.println("After: salary=" + harry.getSalary()); /*
* Test 3: Methods can't attach new objects to object parameters
*/
System.out.println("\nTesting swap:");
var a = new Employee("Alice", 70000); //定义一个类型为var的a,并进行初始化
var b = new Employee("Bob", 60000);
System.out.println("Before: a=" + a.getName());
System.out.println("Before: b=" + b.getName());
swap(a, b); //交换函数
System.out.println("After: a=" + a.getName());
System.out.println("After: b=" + b.getName());
} public static void tripleValue(double x) // doesn't work(不工作)
{
x = 3 * x;
System.out.println("End of method: x=" + x);
} public static void tripleSalary(Employee x) // works
{
x.raiseSalary(200); //x的调用
System.out.println("End of method: salary=" + x.getSalary());
}
//x和y进行交换
public static void swap(Employee x, Employee y)
{
Employee temp = x;
x = y;
y = temp;
System.out.println("End of method: x=" + x.getName());
System.out.println("End of method: y=" + y.getName());
}
} class Employee // simplified Employee class
{
private String name; //实例域定义
private double salary; public Employee(String n, double s) //构造器定义
{
name = n;
salary = s;
} public String getName() //实例域name的访问器方法
{
return name;
} public double getSalary() ////实例域Salary的访问器方法
{
return salary;
} public void raiseSalary(double byPercent)
{
double raise = salary * byPercent / 100;
salary += raise;
}
}

  运行结果如下图:

实验2  测试程序4(5分)

程序代码如下:

 import java.util.*;

  /**
* This program demonstrates object construction.
* @version 1.02 2018-04-10
* @author Cay Horstmann
*/
public class ConstructorTest
{
public static void main(String[] args)
{
// fill the staff array with three Employee objects (用三个employee对象填充staff数组 )
var staff = new Employee[3]; staff[0] = new Employee("Harry", 40000);
staff[1] = new Employee(60000);
staff[2] = new Employee(); // print out information about all Employee objects (打印有关所有员工对象的信息 )
for (Employee e : staff) //foreach循环
System.out.println("name=" + e.getName() + ",id=" + e.getId() + ",salary="
+ e.getSalary());
}
} class Employee
{
private static int nextId; //静态域nextId
private int id;
private String name = ""; // instance field initialization(实例字段intialization)
private double salary; // static initialization block (静态intialization块)
static
{
var generator = new Random();
// set nextId to a random number between 0 and 9999 (将nextId设置为0到999之间的随机值)
nextId = generator.nextInt(10000);
} // object initialization block (对象intialization块)
{
id = nextId;
nextId++;
}
// three overloaded constructors //三个重载的构造
public Employee(String n, double s)
{
name = n;
salary = s;
} public Employee(double s)
{
// calls the Employee(String, double) constructor
this("Employee #" + nextId, s); //this用来引用当前对象
} // the default constructor //错误的构造器
public Employee()
{
// name initialized to ""--see above
// salary not explicitly set--initialized to 0
// id initialized in initialization block
} public String getName() //实例域name的访问器方法
{
return name;
} public double getSalary() //实例域Salary的访问器方法
{
return salary;
} public int getId() //实例域Id的访问器方法
{
return id;
}
}

  运行结果如下图所示:

实验2  测试程序5(5分)

4-6程序代码如下:

import com.horstmann.corejava.*;
// the Employee class is defined in that package (Employees类在该包中定义) import static java.lang.System.*; //静态导入System类
/**
* This program demonstrates the use of packages.
* @version 1.11 2004-02-19
* @author Cay Horstmann
*/
public class PackageTest
{
public static void main(String[] args)
{
// because of the import statement, we don't have to use
// com.horstmann.corejava.Employee here
var harry = new Employee("Harry Hacker", 50000, 1989, 10, 1); harry.raiseSalary(5); // because of the static import statement, we don't have to use System.out here
out.println("name=" + harry.getName() + ",salary=" + harry.getSalary());
}
}

  运行结果如下图:

4-7程序代码如下:

package com.horstmann.corejava;    //将类放入包中

// the classes in this file are part of this package   (这个文件中的类就是这个包中的一部分)

import java.time.*;   //java.time包的引入

// import statements come after the package statement   (import语句位于package语句之后)

/**
* @version 1.11 2015-05-08
* @author Cay Horstmann
*/
public class Employee
{
private String name; //实例域定义
private double salary;
private LocalDate hireDay; public Employee(String name, double salary, int year, int month, int day) //构造器定义
{
this.name = name; //this用来引用当前对象
this.salary = salary;
hireDay = LocalDate.of(year, month, day);
} public String getName() //实例域name的访问器方法
{
return name;
} public double getSalary() //实例域Salary的访问器方法
{
return salary;
} public LocalDate getHireDay() //实例域HireDay的访问器方法
{
return hireDay;
} public void raiseSalary(double byPercent)
{
double raise = salary * byPercent / 100;
salary += raise;
}
}

  运行结果如下图:

4. 实验总结:(10分)

通过第四周的学习,掌握类的定义,熟悉属性、构造函数、方法的作用,掌握用类作为类型声明变量和方法返回值;理解类和对象的区别,类可以看做一个模板,我们可以根据类来创建很多的对象,而这些对象都具有我们在类中定义的方法和属性,类是抽象的,而对象是具体的。可以通过new关键字去实例化对象。还有掌握构造函数的使用,熟悉通过对象名引用实例的方法和属性;理解方法中的形参和实参传递在传递基本类型和引用类型的的差异;理解sstatic修饰符对类、类成员变量及类方法的影响 。通过编程和上机实验理解加java语言是如何体现面向对象编程基本思想,了解类的封装方法,以及加何创建类和对象,了解成员变量和成员方法的特性,掌握O0P方式进行程序设计的方话,了解共的继承性和多态性的作用。 

最新文章

  1. Spring Boot项目使用Flyway
  2. GMU 简单使用一
  3. 聚类算法之BIRCH(Java实现)转载
  4. hdu1018
  5. [vB.NET]为控件添加鼠标悬浮时的提示气泡
  6. (转)Android学习笔记---SQLite介绍,以及使用Sqlite,进行数据库的创建,完成数据添删改查的理解
  7. php检查漏洞防护补丁-防护XSS,SQL,文件包含等多种高危漏洞
  8. java星座、年龄、日期等
  9. android开发 锁屏 真正的锁屏,是go锁屏那种。
  10. POJ 3177 Redundant Paths(重边标记法,有重边的边双连通分支)
  11. .net 文件下载
  12. hadoop集群的搭建与配置(1)
  13. 开机自动挂载 VHD 的方法
  14. nuget pack 时不包含依赖包(而不是引用项目的dll,区别于IncludeReferencedProjects)
  15. 打印pid,写着玩。
  16. IdentityServer4 登录成功后,跳转到原来页面
  17. Python 破解带密码保护的Zip文件
  18. MySQL查询语句报错 sql_mode=only_full_group_by 问题
  19. BZOJ3275Number——二分图最大权独立集
  20. python使用requests发送text/xml报文数据

热门文章

  1. numpy和matplotlib的pyplot函数的简单应用实现
  2. Ubuntu 18.04 安装 python 的 redis 库
  3. 201871010133-赵永军《面向对象程序设计(java)》第一周学习总结
  4. 关于网站登录后的页面操作所携带的不同cookie值
  5. a迭代尾声处理
  6. 通过windows组策略配置时间同步
  7. mysql执行操作时卡死
  8. 在 ASP.NET Core 项目中使用 npm 管理你的前端组件包
  9. python-11-字典的增删改查
  10. jQuery 源码分析(十三) 数据操作模块 DOM属性 详解