配置环境变量
JAVA_HOME的作用:它是指向jdk的目录的,看成一个变量就好了,便于更改。C:\Program Files\Java\jdk1.8.0_171
Path的作用:程序的执行需要使用外部指令javac,但是javac指令仅仅能在JDK安装目录下的bin目录下才能使用,我们编写的程序肯定不在这里,所以需要使javac在任意目录下都能调用。同理java命令也是需要的。%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin
CLASSPATH的作用:当输入import的时候,就需要用到这个环境变量了,是记录已经写好java类库的位置。.;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar
关键字及其语法
成员变量和局部变量的区别
成员变量和局部变量的区别(成员变量和局部变量的名称可以相同,访问时按着就近原则):
1. 位置不同:成员变量在类中方法外;局部变量在方法定义中或者方法声明上。
2. 内存位置不同:成员变量在堆内存中,它有初始化默认值;局部变量在栈内存中,没有初始化默认值,必须定义赋值后才能使用。
3. 生命周期不同:成员变量随着对象的创建而存在,随着对象的消失而消失;局部变量随着方法的调用而存在,随着方法的调用完毕而消失。
匿名对象
匿名对象就是没有名字的对象,使用场景:
1. 调用对象的方法,仅调用一次的时候,调用完毕对象就会被垃圾回收器回收。
2. 匿名对象可以作为实际参数进行传递。
封装
封装:是指隐藏对象的属性和实现细节,仅对外提供公有访问方式。
好处:提高代码的复用性;提高安全性。(举例子电脑的外壳,开机按钮)
封装的方法:
1. 把成员变量使用private来修饰
2. 提供对外的getXxx()和setXxx()方法
package itshuai.com;
public class Student {
private String name;
private int age;
public void setName(String n) {
name = n;
}
public String getName() {
return name;
}
public void setAge(int a) {
age = a;
}
public int getAge() {
return age;
}
}
package itshuai.com;
public class StudentTest {
public static void main(String[] ages) {
Student stu = new Student();
stu.setName("chenshuai");
stu.setAge(25);
System.out.print(stu.getName()+":"+stu.getAge());
}
}
继承
继承:多个类中存在相同的属性和行为时,将这些内容抽取到单独的一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。用extends关键字来表示。
好处:
1. 提高代码的复用性(重复性)。
2. 提高代码的维护性。
3. 让类类存在关系是多态的前提。也是一个弊端,类的耦合性增强了。
注意:
1. 子类只能继承父类的所有非私有的成员方法和成员变量。
2. 子类不能继承父类的构造方法,但是可以通过super关键字去访问。
3. 不要为了部分功能去进行继承,应该使用is a的方法去看是否要继承。
继承中构造方法的关系:
- 子类中的所有构造方法默认都会访问父类中空参数的构造方法。(因为子类继承父类中的数据,可能还会使用父类中的数据,所以子类初始化之前一定要完成父类的初始化。每一条构造方法的第一条语句默认为super(),如果不想访问无参构造,可以使用super(参数),来访问我们写好的父类中构造方法,但this()或super()一定是构造方法中的第一条语句。)
多态
多态:是指某一事物,在不同时刻表现出来的不同形态。
多态的前提和体现:
- 有继承关系
- 有方法重写
- 有父类引用向子类对象
多态中成员访问特点:(只因成员方法可以重写,所有比较特殊)
- 成员变量,编译看左边,运行看左边。(编译能否通过看父类中有没有这个成员变量,运行的结果以父类中的成员变量为准。)
- 成员方法,编译看左边,运行看右边。(如果父类中没有子类的方法,而你去调用子类的方法,那肯定是编译不过去的。如果都有的话,那就是重写。)
- 静态方法,编译看左边,运行看左边。(静态方法和类有关,也不算重写)
this关键字
this:这个关键字代表当前类的对象。this被哪个对象调用,就代表哪个对象。
应用场景:
1. 解决局部变量隐藏成员变量的场景(下面那个场景)
变量的命名规则要做到见名知意,上面封装示例代码的Student就没有(name=n;age=a)。但如果改为name=name;age=age那么得到的值则为默认值,因为根据就近原则,赋值根本不会成功。如果改为Student.name=name,那是静态变量才能这样做,这时可以用this。
super关键字
super:代表父类存储空间的标识。(可以理解为父类引用,可以操作父类成员。)
super():调用父类的无参构造方法。
abstract关键字
abstract:用来定义抽象类和抽象方法的。
当我们需要用到一个接口时,只想实现其中的一个接口。可以先用抽象类用空方法来实现这个接口,然后编写这个抽象类的子类,只重写那个方法,这叫做适配器。
static关键字
static:可以修饰成员变量和成员方法。
特点:
1. 随着类的加载而加载(main方法)
2. 优先于对象存在
3. 被类的所有对象共享
4. 可以通过类名调用,也可以通过方法名来调用
注意事项:
1. 在静态方法中是没有this关键字的(this是创建对象后才会有)
2. 静态方法中不能访问成员变量和成员方法;非静态方法可以访问静态或非静态的变量和方法
final关键字
final关键字:由于继承中的方法有一个现象:方法的重写,所以父类的功能就会被子类重写的方法覆盖掉,有时候我们不想让子类覆盖掉此功能,就可以用final。
特点:
1. 修饰类:被final修饰的类称为最终类,它不能被继承。绝育。
2. 修饰方法:被final修改的方法不能被重写。
3. 修饰变量:被final修饰的变量不能被重新赋值。变成自定义常量了。
注意:
- final可以修饰成员变量(权限修饰符修饰成员变量没有意义,方法内部本来就不可以见)。被修饰的基本数据类型就是值不可变,引用数据类型变量则是地址值不能变(重新new,进行创建同名的引用变量),但值可以重新赋值。
- 修饰的变量需要在构造方法之前进行赋值。
构造方法
作用:给对象的数据进行初始化
格式:
1. 方法名和类名相同
2. 没有返回值类型,连void都没有,自然也不需要return
导包
导包:不同包下的类之间的访问,每次使用不同包下的类的时候,都需要加包的全路径,所有java提供了导包的功能。
导包的格式:import 包的名称;
访问修饰符
访问修饰符包括:
1. private(被它修饰的成员变量和成员方法只能在本类中访问)
1. 默认
1. protected (主要便于不同包下的子类来访问本类)
1. public
常用类
API
api:应用程序编程接口
理解举例:编写一个机器人程序去控制机器人踢球,程序需要向机器人发出左转,右转,射门等动作。没有编程经验的人很难想象会怎么编写程序,对于有经验的人则知道机器人公司一定会提供一些用于控制机器人的java类,这些类定义了机器人的动作,其实这些java类就是机器人厂商提供给应用编程人员的接口。把它称为机器人接口。
Object
Object:是所有类的超类。
方法:
- public int hashCode():返回该对象的哈希码值。支持此方法是为了提高哈希表(例如 java.util.Hashtable 提供的哈希表)的性能。(哈希值是根据哈希算法计算出来的一个值,这个值和地址有关,但不是实际地址,可以理解为地址)
- public final Class
Scanner
Scanner:用于接收键盘数据。(JDK5版本后的)
方法:
- public Scanner(InputStream source):这是一个构造方法。构造一个新的 Scanner,它生成的值是从指定的输入流扫描的。取自该流的字节通过底层平台的默认字符集转换成字符。我们的命令Scanner sca = new Scanner(System.in);就是用的这个方法。
- public boolean hasNextXxx():判断下一个是否为某种类型的元素。
- public Xxx nextXxx():获取下一个元素。(如果获取两个元素,第一个元素不为字符串,第二个元素为字符串,则获取的第二个字符串为/n是按键enter)
package itshuai.com;
import java.util.Scanner;
public class ScannerDemo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
if(sc.hasNextInt()) {
int s = sc.nextInt();
System.out.println(s);
}else {
System.out.println("请输入一个整数");
}
}
}
String
String:就是由多个字符组成的一串数据,也可以看成是一个字符数组。
特点:
- 字符串字面值”abc”也可以看成是一个字符串对象。
- 字符串是一个常量,一旦赋值,就不能被更改。(注意是值不能改变,不是引用)
构造方法:
- public String():初始化一个新创建的 String 对象,使其表示一个空字符序列。注意,由于 String 是不可变的,所以无需使用此构造方法。
- public String(byte[] bytes):通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。新 String 的长度是字符集的函数,因此可能不等于 byte 数组的长度。
- public String(byte[] bytes,int index,int length):通过使用平台的默认字符集解码指定的 byte 子数组,构造一个新的 String。新 String 的长度是字符集的函数,因此可能不等于该子数组的长度。
- 上面两个构造方法的参数也可以是char类型
package itshuai.com;
public class StringDemo {
public static void main(String[] args) {
String a = new String();
System.out.println(a); //
byte[] by = {97,98,99};
String b = new String(by);
System.out.println(b); //abc
String c = new String(by,1,2);
System.out.println(c); //bc
char[] ch = {'q','w','e'};
String d = new String(ch);
System.out.println(d); //qwe
String e = new String(ch,1,2);
System.out.println(e); //we
}
}
String s = new String(“hello”);和String s = “hello”;两者的区别是什么:前者其实是需要两个地址值才能找到值的(前者需要创建两个对象,后者需要创建一个)。见下图
字符串如果是变量相加,先开空间,再拼接。如果是常量相加,先拼接,然后在常量池中找,如果有就直接返回地址值,没有就创建。见下图
package itshuai.com;
public class StringDemo {
public static void main(String[] args) {
String a = "Hello";
String b = "World";
String c = "HelloWorld";
System.out.println(c == a + b); //false
System.out.println(c == "Hello" + "World"); //true
}
}
方法:
1. 判断功能:
- public boolean equals(Object anObject):将此字符串与指定的对象比较,区分大小写。当且仅当该参数不为 null,并且是与此对象表示相同字符序列的 String 对象时,结果才为 true。(覆盖 Object 中的 equals)
- public boolean equalsIgnoreCase(String anotherString):将此 String 与另一个 String 比较,不考虑大小写。
- public boolean contains(String s):判断大的字符串中是否包含小的字符串
- public boolean startsWith(String prefix):测试此字符串是否以指定的前缀开始。
- public boolean endsWith(String suffix):测试此字符串是否以指定的后缀结束。
- public boolean isEmpty():判断字符串是否为空,是否为”“。
2.获取功能
- public int length():返回此字符串的长度。长度等于字符串中 Unicode 代码单元的数量。
集合
为什么需要集合
java是面向对象语言,我们就需要对对象进行存储,对象数组又是固定长度的,所以我们需要集合。
数组和集合的区别:
- 长度不同。数组长队固定,集合长度可变。
- 内容不同。数组存储的是同一类型的元素,集合可以存储不同类型的元素。
- 数据类型不同。数组可以存储基本数据类型和引用数据类型,集合只能存储引用类型。
异常
什么是异常
异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的。当程序出现不正常的问题,jvm就会把问题的名称、原因、位置输出到控制台,但是程序就会停止,这是jvm默认处理的方式。告诉我原因很好,但是程序不能停止啊,我下面还有要运行的东西呢。所以我们需要自己处理异常。
如何自己处理
异常的分类以及处理:
1. error—错误 : 是指程序无法处理的错误,表示应用程序运行时出现的重大错误。例如jvm运行时出现的OutOfMemoryError以及Socket编程时出现的端口占用等程序无法处理的错误。
2. Exception — 异常 :异常可分为运行时异常和编译异常
- 运行时异常:即RuntimeException及其之类的异常。这类异常在代码编写的时候不会被编译器所检测出来,是可以不需要被捕获,但是程序员也可以根据需要(可以改代码,代码严谨后不会出现这种问题。)进行捕获抛出。常见的RUNtimeException有:NullpointException(空指针异常),ClassCastException(类型转换异常),IndexOutOfBoundsException(数组越界异常)等。
- 编译异常:RuntimeException以外的异常。这类异常在编译时编译器会提示需要捕获,如果不进行捕获则编译错误。常见编译异常有:IOException(流传输异常),SQLException(数据库操作异常)等。
自己处理异常的方法:
- try…catch…finally
- throws 抛出
IO
File类
File的概述:文件和目录路径名的抽象表示形式。(抽象表示形式,未必是真实存在的)
构造方法:
- public File(String pathname):根据一个路径来得到File对象。
- public File(File parent,String child):根据一个File对象和一个目录或文件名来得到一个对象。
- public File(String parent,String child):根据一个路径和一个目录或文件名来得到一个对象。
方法:
创建功能:
- public boolean createNewFile() throws IOException:创建文件
多线程
什么是多线程
如果程序有多条执行路径,那么该程序就是多线程程序。
进程:可以通过任务管理器查看,是指正在运行的程序。进程是系统进行资源分配和调用的独立单位,每一个进程都有它的内存空间和系统资源。
线程:一个进程中又可以执行多个任务,而这个任务我们可以看作是一个线程。可以把线程看作进行的执行单元。是程序使用cpu的基本单位。
多线程的意义:多线程能满足程序员编写高效率的程序来达到充分利用CPU的目的。
举例:扫雷,迅雷,jvm虚拟机(至少启动了垃圾回收线程和主线程)。
实现多线程程序
如何实现:线程是依赖进程而存在的,所以我们应该先创建一个进程出来。而进程是由系统创建的,java不能调用系统功能,是通过调用c/c++写的程序来创建进程实现多线程的。
实现多线程的两种方式:
- 继承Thread类,该子类重写run方法,然后创建该类对象,启动线程。代码如下:
package itshuai.com;
public class MyThread extends Thread {
@Override
public void run() {
//自己写代码,一般被线程执行的代码肯定是比较耗时的。
for(int i=0;i<=100;i++) {
//getname()使用方法
System.out.println(getName()+"---"+i);
}
}
}
package itshuai.com;
public class MyThreadDemo {
public static void main(String[] args) {
MyThread my1 = new MyThread();
MyThread my2 = new MyThread();
//run()仅仅是封装被线程执行的代码,start()才是启动线程,然后jvm调用该线程的run()方法。
//更改默认线程名
my1.setName("线程1");
my2.setName("线程2");
//开始启动线程
my1.start();
my2.start();
//获取main所在的线程名
System.out.println(Thread.currentThread().getName());
}
}
- 实现Runnable接口(解决了单继承的局限性;适合多个程序去处理统一资源的情况,只创建了一个对象),自定义类实现接口,实现了run(),创建这个类的对象,最后创建Thread类的对象并将对象作为参数。代码如下:
package itshuai.com;
public class MyRunnable implements Runnable {
@Override
public void run() {
for(int i=0;i<=100;i++) {
System.out.println(Thread.currentThread().getName()+"---"+i);
}
}
}
package itshuai.com;
public class MyThreadDemo {
public static void main(String[] args) {
MyRunnable my = new MyRunnable();
Thread th1 = new Thread(my,"线程1");
Thread th2 = new Thread(my,"线程2");
th1.start();
th2.start();
}
}
线程调度
假如计算机只有一个cpu,cpu在某一时刻只能执行一条指令,那线程只有得到cpu的时间片,才能执行指令,
线程调度模型(java使用的是第二种):
- 分时调度模型(所有线程轮流使用)
- 抢占式调度模型(优先让优先级高的线程使用cpu)
线程调度的方法(默认为5,最大为10,最低为1):
- public final void setPriority(int newPriority)
- public final int getPriority()
线程控制
线程控制的方法:
- 线程睡眠(这个方法在重写的run()里面,单位为毫秒):public static void sleep(long millis) throws InterruptedException
- 等待这个线程执行完毕再执行其他线程:public final void join() throws InterruptedException
- 可以在一定程度上让线程轮流执行:public static void yield()
- 将线程标记为守护线程(在线程调用钱标记,守护线程参数为true,当线程都为守护线程时,jvm会退出线程执行):public final void setDaemon(boolean on)
- 中断线程(把线程状态中止,并抛出一个异常,然后执行catch语句在接着执行其他语句):public void interrupt()
线程的生命周期
GUI
GUI:图片界面显示
CUI:命令行操作
java为GUI提供的对象都在:
- java.awt(需要调用本地系统方法,实现功能。属于重量级控件。)
- javax.swing(在awt基础上建立的一套图形系统,增强了移植性,属于轻量级控件。)
Frame类的使用
示例代码如下:
package itshuai.com;
import java.awt.Frame;
public class FrameDemo {
public static void main(String[] args) {
//第一步,创建窗体对象,构造一个不可见的窗体
Frame fr = new Frame();
//设置窗体标题
fr.setTitle("HelloWorld");
//设置窗体大小,默认为像素
fr.setSize(300, 300);
//设置窗体位置
fr.setLocation(1000, 500);
//调用一个方法,让窗体可见
fr.setVisible(true);
System.out.println("哈哈");
}
}
网络编程
什么是网络编程
网络编程就用来实现网络互连的不同计算机运行的程序间的数据交换。
什么是网络模型
计算机网络之间以何种规则进行通信,就是网络模型研究的问题。网络模型一般有两种:
- OSI参考模型
- TCP/IP参考模型
网络通讯的三要素
- IP地址
网络中计算机的唯一标识, - 端口
一般是指的逻辑端口,每个网络软件都有一个逻辑端口。 - 协议
通信的规则,UDP(不可靠,速度快,数据打包);TCP(可靠,建立通道,大文件传输)
Socket 网络套接字
Socket包含了IP和端口。
Socket原理机制:
- 通讯两端都要有Socket
- 网络通信其实就是Socket之间的通讯
- 数据在两个Socke间通过IO传输
反射
什么是类的加载
类的加载:当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。
加载就是将class文件读入内存,并为之创建一个Class对象。任何类被使用时系统都会创建一个Class对象。
连接分为验证,准备,解析三步,验证是否有正确的内部结构。准备则是负责为类的静态成员分配内存,并设置默认初始化值。解析是将类的二进制数据中的符合引用替换为直接引用(将等号替换为地址值指向引用?)。
初始化就是通过new创建类的实例,进行初始化。
什么时候会进行类的加载
类加载的时机:
1. 创建类的实例
1. 访问类的静态变量,或者为静态变量赋值
1. 调用类的静态方法
1. 初始化某个类的子类
1. 直接使用java.exe命令来运行某个主类
1. 使用反射方式强制创建某个类或接口对应的java.lang.Class对象
什么是类加载器
类加载器:负责将class文件加载到内存中,并为之生成对应的Class对象。
类加载器的组成:
1. 根类加载器——也成为引导类加载器,负责java核心类的加载。(System String等,在jdk的lib中的rt.jar中)
1. 扩展类加载器——负责jre的扩展目录jar包的加载。(在jdk中lib的ext目录下)
1. 系统类加载器——负载在jvm启动时加载来自java命令的class文件,还有classpath环境变量所指定的jar包和类路径。
什么是反射机制
反射(reflection):是指在运行状态中,对任意一个类,都能知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。(原来我们使用构造方法、成员变量、成员方法都是在.java文件中操作的,现在则是通过.class文件去使用,那我们首先需要得到.class文件的对象,也就是Class对象)
如何获取Class对象
演示Person类:
package itshuai.com;
public class Person {
private String name;
int age;
public String address;
public Person() {
}
private Person(String name, int age){
this.name = name;
this.age = age;
}
public Person(String name,int age,String address) {
this.name = name;
this.age = age;
this.address = address;
}
public void show() {
System.out.println("show方法执行了");
}
private void method(String s) {
System.out.println("method"+s);
}
public String getString(String s,int i) {
return s+"________"+i;
}
private void function() {
System.out.println("function");
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", address=" + address + "]";
}
}
获取Class文件对象有三种方法:
1. Object类的getClass()方法
1. 数据类型的静态属性class
1. Class类中的静态方法
package itshuai.com;
public class Reflection {
public static void main(String[] args) throws ClassNotFoundException {
//已经创建好了一个Person
Person per = new Person();
Class reflection1 = per.getClass();
System.out.println(reflection1);
//第二种
Class reflection2 = Person.class;
System.out.println(reflection2);
//第三种(适用于开发,因为字符串的名字可以写在配置文件中)
Class reflection3 = Class.forName("itshuai.com.Person");
System.out.println(reflection3);
}
}
如何使用Class对象
通过反射来创建对象(使用Class对象来获取能够表示类的构造方法信息的Constructor对象,并使用这个能表示Person类的构造方法的对象来创建Person的对象并调用其方法):
package itshuai.com;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Reflection {
public static void main(String[] args) throws Exception {
//通过类的字符串名称来获取对应的Class对象
Class per = Class.forName("itshuai.com.Person");
//这是获取所有的公共构造方法并存在数组中并遍历
//public Constructor<?>[] getConstructors() throws SecurityException
Constructor[] cons = per.getConstructors();
for(Constructor con:cons) {
System.out.println(con);
}
//这是获取所有的构造方法并存在数组中并遍历
//public Constructor<?>[] getDeclaredConstructors() throws SecurityException
Constructor[] cons = per.getDeclaredConstructors();
for(Constructor con:cons) {
System.out.println(con);
}
//获取单个公共的构造方法,注意参数为数据类型的Class对象,根据参数来决定获取哪个构造方法
//public Constructor<T> getConstructor(Class<?>... parameterTypes) throws NoSuchMethodException,SecurityException
Constructor con = per.getConstructor(String.class,int.class,String.class); //获取单个的构造方法
//使用此类对象表示的构造方法来创建对象。并调用方法
//public T newInstance(Object... initargs) throws InstantiationException,IllegalAccessException,IllegalArgumentException,InvocationTargetException
Object pe = con.newInstance("陈帅",26,"衡水");
Person p = (Person)pe;
p.show();
//获取单个私有的构造方法,通上面获取公共的构造方法格式一样
Constructor con = per.getDeclaredConstructor(String.class,int.class); //获取单个的构造方法,会报非法访问异常
//需要调用一个方法
con.setAccessible(true);
//使用Constructor类表示的Person构造方法信息的对象来创建Person的对象并调用方法。
Object pe = con.newInstance("陈帅",26);
Person p = (Person)pe;
p.show();
}
}
通过反射来对变量赋值:
package itshuai.com;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class Reflection {
public static void main(String[] args) throws Exception {
//通过类的字符串名称来获取对应的Class对象
Class per = Class.forName("itshuai.com.Person");
//获取所有的成员变量
//public Field[] getDeclaredFields() throws SecurityException
Field[] fis = per.getDeclaredFields();
for(Field fi:fis) {
System.out.println(fi);
}
//获取单个的成员变量并赋值
//public Field getDeclaredField(String name) throws NoSuchFieldException,SecurityException
Field fi = per.getDeclaredField("name");
//将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
//public void set(Object obj,Object value) throws IllegalArgumentException,IllegalAccessException
//需要创建一个person的对象
Constructor con = per.getConstructor();
Object pe = con.newInstance();
//对私有的对象上面的name字段赋值
fi.setAccessible(true);
fi.set(pe, "陈帅");
System.out.println(pe);
}
}
通过反射来调用方法:
package itshuai.com;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class Reflection {
public static void main(String[] args) throws Exception {
//通过类的字符串名称来获取对应的Class对象
Class per = Class.forName("itshuai.com.Person");
//获取此类所有的方法
//public Method[] getDeclaredMethods() throws SecurityException
Method[] mes = per.getDeclaredMethods();
for(Method me:mes) {
System.out.println(me);
}
//获取单个方法
//public Method getDeclaredMethod(String name,Class<?>... parameterTypes) throws NoSuchMethodException,SecurityException
Method me = per.getDeclaredMethod("method",String.class);
//对带有指定参数的指定对象调用由此 Method对象表示的底层方法。
//public Object invoke(Object obj,Object... args) throws IllegalAccessException,IllegalArgumentException,InvocationTargetException
//通过反射来创建一个对象
Constructor con = per.getConstructor();
Object pe = con.newInstance();
//使用方法的对象通过类的对象和参数来调用方法,如果调用的是有返回值的方法,进行接受一下就可以了
me.setAccessible(true);
me.invoke(pe, "方法调用了");
}
}
单元测试
什么是单元测试
单元测试:单元测试是指在计算机编程中,针对程序模块(软件设计的最小单位)来进行正确性的检验工作。
特点:
- 程序单元是应用的最小可测试部件,通常采用基于类或者类的方法进行测试
- 程序单元和其他单元是互相独立的
- 单元测试的执行速度很快
- 单元测试发现问题后,比较好定位
- 单元测试通常由开发人员来完成
- 通过了解代码的实现逻辑进行测试,通常称为白盒测试
JUnit单元测试框架
JUnit是基于java语言的主流单元测试框架。
TestNG单元测试框架
TestNG比JUnit更强大。