Java_1.8_API
Java Application初步
- Java的源文件后缀是**.java**。类**.class**是源文件的基本组成部分
- 一个源文件中最多只能有一个public类,且其名字与文件名相同
- Java Application的执行入口是main()方法。其的书写方法是:public static void main(String args[]){...}
Java变量
按被声明的位置划分
- 局部变量:方法或语句块内部定义的变量(包括形参),局部变量在栈stack里分配内存。
- 成员变量:方法外部、类的内部定义的变量,非静态成员变量在堆heap里分配内存,静态成员变量在数据区data segment里分配内存。
- 注意:类外面(与类对应的大括号外面)不能有变量的声明
按所属的数据类型划分
- 基本数据类型变量
- 引用数据类型变量
- 变量若没有初始化,则默认为0,false,null
基本数据类型变量
- 布尔型boolean:只允许取true和false,不能用0和非0代替
- 整型byte,short,int,long(Java里没有无符号整型):整型常量默认为int;声明long型常量后必须加'l'或'L',否则会出错
- 浮点型float,double:浮点型常量默认为double;声明float型常量需加'f'或'F',否则会出错
引用数据类型变量
基础数据类型以外的所有类型都是引用数据类型
- 引用可以看成是C语言中的指针
- 引用指向的值全都放在堆内存里(即new出来的值都放在堆内存里),若声明了一个引用但没有new,则其值为null,即不指向任何值
数组
*数组不是基本类型,是引用类型,所以数组是存放在堆heap中的
- Java中声明数组的时候不能指定长度,如下
int i[5];//非法
int s[]或者int[] s;//合法
s = new int [5];//此时堆空间分配五个空间
复制代码
- s.length为数组s的长度
- 如果数组存放的是引用型数据,则需像下面这样使用
/*
动态初始化
Data days[];
days = new days[3];
days[0] = new Data(2018, 4, 2);
*/
//或者静态初始化
Data days[] = {
new Data(2018, 4, 2);
new Data(2018, 4, 3);
new Data(2018, 4, 4);
}
//或者
int[] s = new int[9];
复制代码
二维数组
//多维数组的初始化时从高维到低维的
int a[][] = new int[3][];
a[0] = new int[2];
a[1] = new int[4];
a[2] = new int[3];
/*
错误示范
int t1[][] = new int[][3];
*/
//静态初始化
int a2[][] = { {1,2}, {4,1,5}, {2,5,4,1,5,2} };
/*
错误示范
int t2[3][2] = { {1,2}, {3,4}, {5,6} };
*/
//动态初始化
int a3[][] = new int[3][5];
复制代码
==需要注意的是,java中的多维数组的内存并不是像c语言中的多维数组一样连续存放的,只有单一维度才是连续存放的。==
数组的复制
利用java.lang.System中的arraycopy可以实现数组的复制
//调用方法
System.arraycopy(源数组, int 复制起点, 目标数组, int 复制起点, 复制元素个数)
复制代码
变量类型的强制转换
例如要将一个字符型变量i强制转化为double型,则
double d = Double.parseDouble(i);
复制代码
运算符
- 逻辑运算符:!-逻辑非,&-逻辑与,|-逻辑或,^-逻辑异或(两者相同时为假),&&-短路与,||-短路或(与C语言的与或相同)
- 赋值运算符=:可以将整型常量赋值给byte,short,char等类型变量,只要不超出范围即可
- 字符串连接符+:'+'除了可以用来做算术加法,还可以对字符串进行连接操作。==PS:'+'运算符两侧操作数只要有一个是String类型,系统就会自动将另一个操作数转化为字符串然后进行连接。==
方法
格式:[修饰符1 修饰符2 ...] 返回值类型 方法名(形式参数列表) { Java 语句; ... ... } 调用格式:对象名.方法名(实参列表) return语句结束方法的执行
方法的重载Overload
一个类中可以定义多个返回类型相同,名字相同,但参数个数或类型不相同的方法,例如:
class Max {
void max(int a, int b) {
System.out.println( a > b ? a : b );
}
void max(double a, double b) {
System.out.println ( a > b ? a : b );
}
void max(char a, char b, char c) {
...
}
/*
int max(int a, int b) {
return a > b ? a : b ;
}
这个是错的,因为返回类型是int不是void
*/
}
复制代码
调用Max类中的max方法时,编译器会通过判断max中的参数列来判断调用哪一个max方法。
方法的重写Overwrite/Override
- 在子类中可以根据需要对从基类继承来的方法进行重写。
- ==重写的方法必须与原方法具有相同的名称,返回类型,参数列表。== 十分容易在这里出错,所以每次重写时直接复制父类的方法声明。
- 重写的方法不能使用比原方法更严格的访问权限。
异常处理
try {
//可能出错的代码
} catch(SomeException1 e) {
//出现异常SomeException1时的处理
} catch(SomeException2 e) {
// e可以理解为SomeException2类型的形参,用来当异常出现时接收该异常
} finally {
//无论出不出错都会执行的代码
}
复制代码
==当异常出现时,程序会立刻停止当前的流程,根据异常的类型去执行相应的catch代码,然后直接跳去执行finally段代码。==
通常在finally语句中执行资源清楚工作,如:
- 关闭打开的文件
- 删除临时文件
- ······
Java中定义的异常类有如下分类:
graph TD
A[Throwable]-->B(Error)
A[Throwable]-->C(Exception)
C(Exception)-->D(RuntimeException)
C(Exception)-->E(其他)
复制代码
- 其中Throwable类是所有异常类的基类,只要是继承它的类,就可以被抛出
- Error类为系统的内部错误,无法干涉,处理不了的错误
- Exception类是可以人为处理的异常,
- RuntimeException类是程序在运行时发生的异常,经常出现,这种异常,可以catch,也可以不catch,因为这类异常出现十分频繁
- 除RuntimeException、Error外的其他异常,必须catch
Java在处理异常的时候,调用printStackTrace方法可以将异常一层一层地打印出来(与python类似)
自定义异常
步骤:
- 通过继承Exception类声明该类为异常类,格式如下
class MyException extends Exception {
public MyException(String message) {
super(message);
//message为错误的相关信息
}
}
复制代码
- 在需要抛出自定义异常的时候,生成并抛出,如下
public void test(int i) {
if(i<0) {
throws new MyException("i不能小于0");
}
}
复制代码
注意事项
- catch异常的时候,如果catch了Exception,那么这个catch后面的其他catch代码段就失效了,因为Exception是所有可以catch的Exception的基类,所以,catch的异常类越细越好。==即先抛小的,再抛大的。==
- 如果一个方法可能会抛出某种异常,但是你又不想在这个方法内部处理它,那么可以在声明时使用throws关键字,然后在调用该方法时再用try,catch来捕获异常,如下
void f() throws IOException {
...
//该方法可能抛出IOException
}
public static void main(String argsp[]) {
try {
f();
} catch (IOException e) {
}
}
复制代码
- 当一个方法抛出异常后,剩余下来的语句不会被执行
- 重写有抛出异常的方法时,必须抛出相同类型的异常或者不抛出
关键字
this 关键字
类似于Python中的self,this指向调用某方法的对象本身,即其值为当前对象的引用
public class Leaf {
int i = 0;
//Leaf方法中的this.i指的是对象的i,即上面声明的i
Leaf(int i) {
this.i = i;
}
Leaf increament() {
i++;
return this;
//返回的是Leaf的引用
}
void print() {
System.out.println("i = " + i);
}
public static void main(String args[]) {
Leaf leaf = new Leaf(100);
leaf.increament().increament().print();
}
//输出 i = 102
}
复制代码
补充:在一个类中,如果使用this(argument_list)则代表调用了该类中的某个构造方法,具体是哪个构造方法由参数列argument_list决定
static 关键字
- 在类中,用static声明的成员变量称为静态成员变量。
- 用static声明的方法为静态方法,在调用该方法时不会将对象的引用(this)传递给它,所以在静态方法中不能访问非静态成员。(类似于Python中的staticmethod)
- 可以通过对象.静态成员或者类名.静态成员来访问静态成员。
package 关键字
为便于管理大型软件系统中数目众多的类,解决类的命名冲突问题,Java引入包(package)机制,提供类的多重类命名空间
- 若想将一个类放入某个包中,在这个类的源文件的第一行写:
package pkg1.pkg2.pkg3;
复制代码
- 注意:
- 必须保证该类的.class文件放在正确的目录下即pkg1/pkg2/pkg3...
- 将该类的源文件.java移至其他目录下,否则该类的源文件可能会产生影响
- class文件的最上层包的父目录必须位于classpath下,即com上一级目录在classpath下
- 用cmd执行的时候也需要写全包名
打包jar包
在cmd里定位到想打包的包的com的上一级目录,然后输入命令
jar -cvf 名字.jar *.*
生成的jar包就和com在同一个目录下,此时再将.../com/名字.jar 加入到classpath里就可以使用jar包里面的内容了
import 关键字
- 想访问某一个包内的类可以:
import pkg1.pkg2....具体类名;
//或者
import pkg1.pkg2....*;
//这种方法可以访问包内所有的类
复制代码
super 关键字
- 利用super.fatherMethod()可以引用基类中的方法
final 关键字
被final关键字修饰的变量、形参无法被改变,被修饰的方法无法被重写,被修饰的类无法被继承。类似于C语言中的const
类
常用类
String类
String类代表==不可变==的字符序列
- 因为String类不可变,所以对该类的对象进行操作的时候,效率会比较低
StringBuffer类
StringBuffer代表==可变==的字符序列
基础类型包装类
不同于基础类型的是,其包装类是存放在堆heap内存中的
Math类
该类提供了一系列静态方法用于科学计算,其方法的参数和返回值的类型一般为double
File类
代表系统文件名(路径或文件名),而不是文件 *File中的静态属性String separator存储了当前系统的分隔符,windows下是'',unix下是'/'。==然而不论是在windows还是UNIX,都写'/'就可以。==
枚举类型Enum类
//使用方法
//括号内为该枚举类型的可能取值
public enum classname (a, b, ..) {
//变量test只能取括号内的值
classname test = classname.a;
switch(test) {
case a:...;
case b:...;
}
}
复制代码
//构造方法
public File(String pathname)
//以pathname为路径创建一个File对象,如果pathname是相对路径,
复制代码
类的继承Inherit与权限控制
//继承的语法
//========NewClass继承了SuperClass内的所有成员========
class NewClass extends SuperClass {...}
复制代码
- 通过继承,子类拥有了**基类(superclass)**或者说父类的所有成员(即成员变量和方法)
- Java只允许单继承不允许多继承
访问控制--Java权限修饰符
Java权限修饰符置于类的成员定义前,用来限制其他对象对该类成员的访问权限。
- private:private成员只能在类的内部访问。
- default:default成员可以在类的内部以及同一个包内访问。
- protected:protected成员可以在类的内部、同一个包内、子类内访问。
- public:public成员在任何地方都可以访问。
PS:class只可以用public和default修饰,并且,被default修饰的class只可以在同一个包内部的类访问
构造方法
类中有一个与类同名的方法,叫做构造方法(无返回类型),如:
public class Person {
int id;
int age;
Person(int _id, int _age) {
id = _id;
age = _age;
}
}
复制代码
上例中,Person类中的同名方法Person(int _id, int _age)称为构造方法,此方法是在new一个新的Person类是调用的,如:
Person Mike = new Person(10086, 20)
复制代码
上述过程定义Mike时调用了Person类中的构造方法
继承中的构造方法
- ==子类的构造过程中必须调用基类的构造方法。==
- 子类在其构造方法中使用super(argument_list)调用基类的构造方法(++调用哪个构造方法由argument_list决定++),并且必须写在子类构造方法的第一行。
- 也可以使用this(argument_list)调用本类其他构造方法。
- 如果子类中没有显式调用基类的构造方法,则默认调用基类中无参构造方法,若基类中没有无参构造方法,则编译出错。
object类
- object类是所有Java类的根基类
- 如果类的声明未使用extends声明其基类,则默认object类为其基类
- object类中有一个toString方法,该方法默认返回调用它的对象的类的名字,通常情况下要将toString方法重写,然后返回当前对象的有关信息。
System.out.println("Person = " + p1);
//当进行String与其他数据类型的连接操作时,默认调用toString方法,即上面的代码等价于
//System.out.println("Person = " + p1.toString)
复制代码
- objcet类中的equals方法需要自己重新定义比较方式。字符串与字符串使用equals方法,默认判断两个字符串是否相同
对象转型casting
- 一个基类的引用类型可以指向其子类的对象,但这个引用不能访问子类中新增加的成员(属性和方法)
- 可以通过使用 a instanceof b 来判断a所指向的对象是否属于b类或者b的子类
- 子类的对象可以当作基类的对象来使用,称为向上转型upcasting,反之称为向下转型downcasting
class Animal {
public String name;
Animal(String name) {
this.name = name;
}
}
class Cat {
public String eyesColor;
Cat(String name, String eyesColor) {
super(name);
this.eyesColor = eyesColor;
}
}
class Dog {
public String furColor;
Dog(String name, String furColor) {
super(name);
this.furColor = furColor;
}
}
public class Test {
public static void main() {
Test t = new Test();
//定义t可以使t访问方法f
Animal a = new Animal("animal");
Cat c = new Cat("cat", "bule");
Dog d = new Dog("dog", "black");
t.f(a);
t.f(c);
t.f(d);
//因为c和d都是Animal的子类对象,所以可以作为参数Animal x传入方法f
}
public void f(Animal x) {
System.out.println("name = " + x.name);
if(x instanceof Cat) {
System.out.println("eyesColor = " + x.eyesColor);
}
else if(x instanceof Dog) {
System.out.println("furColor = " + x.furColor);
}
}
}
复制代码
多态Polymoph(也叫动态绑定、迟绑定)———面向对象的核心
动态绑定是指,在程序执行过程期间(非编译期间),判断所引用对象的实际类型,根据其实际类型调用对应的方法。
多态存在的必要条件
- 要有继承
- 要有重写
- 父类引用指向子类对象
满足以上条件后,当调用父类中被重写的方法时,会自动改为调用子类中对应的方法
抽象类
被abstract关键字修饰的类或方法叫做抽象类或抽象方法。
- 抽象类不能被实例化。(即这个类是不完整的,需要声明它的子类,并由子类来完善它自己)抽象类必须被继承。
- 抽象方法只需要声明,不需要实现。(即只需要声明有这样的一个方法就行,具体怎么实现,交给子类去重写)抽象方法必须被重写。
抽象类存在的意义:抽象类就像一个未完成的模型,它提供了该类所必须的某些成员与属性。
抽象方法存在的意义:这个方法是每个子类都会有的,但具体实现因类而异,所以它提供一个空的模板,想要怎么重写是子类的事。
接口 interface
接口可以看成是一中特殊的抽象类,它里面只有常量(即public static final修饰的变量)并且默认为常量,和抽象方法的定义(没有实现),并且这些方法必须用public修饰,例如:
public interface Runner {
public static final int id = 1;
//方法不需要abstract修饰
public void run();
public void stop();
}
复制代码
- 一个接口可以继承另一个接口,并添加新的属性与方法,但不可以继承类
- 接口与实现类之间存在多态性,例如:
//student,teacher类都实现了painter(内含方法paint,eat),singer接口(内含方法sing,sleep)
public class Test {
public static void main() {
Singer s1 = new Student("le");
s1.sing();
s1.sleep();
//此时s1为接口singer类型的引用,但当s1调用sing和sleep方法的时候,调用的却是Student中sing,sleep方法的具体实现
Singer s2 = new Teacher("steven");
s2.sing();
s2.sleep();
//类似地,s2调用的是Teacher中sing,sleep方法的具体实现。但要注意的是,s1,s2都只能调用在Singer接口中出现过的方法
Painter p1 = (Painter)s2;
p1.paint();
p1.eat();
//通过强制类型转换,现在p1可以调用s2中paint,eat方法的具体实现,但是不能调用其他没有在Painter接口中出现过的方法
}
}
复制代码
- 类使用implements关键字来实现接口,例如
class A extends B implements C, D, E {...}
复制代码
容器API
容器API类图结构如下:
graph BT
A[HashSet]-->B[interface Set]
C[LinkedList]-->D[interface List]
E[ArrayList]-->D
B-->F[interface Collection]
D-->F
G[HashMap]-->H[interface Map]
复制代码
Collection接口
- Collection接口定义了存取一组对象的方法,其子接口Set,List分别定义了存储方式。
- Set中的数据对象没有顺序且不可以重复。
- List中的数据对象有顺序且可以重复。
注意,collection中只能存放对象
- 使用Collection接口的remove,contains等方法的时候,需要比较两个对象是否相等,这涉及到了equals和hashcode方法。对于自定义的类型,需要重写equals和hashcode方法来定义对象相等的规则。(相等的对象必须有相同的hashcode)
Set接口
Set接口实现了Collection接口,但是没有新增额外的方法,且实现Set接口的容器类中的元素是没有顺序且不重复的。
- Java中提供的Set容器类有HashSet,TreeSet等。
List接口
- 实现List接口的容器类中的元素是可重复且有序的。
- List容器中的每个元素都对应有一个整型序号记录该元素的位置,可以根据序号存取容器中的元素。
- Java中提供 的List容器类有ArrayList,LinkedList等。
Map接口
- Map接口定义了存储“键(key)——值(value)映射对”的方法。
- 实现Map接口的容器类有HashMap、TreeMap等。
- 键值是Map实现类的对象的标识,所以键值不能重复。
- Map中的key和value都只能是对象,不能是其他的。
Iterator接口
- 所有实现了Collection接口的容器类都有一个Iterator方法用以返回一个实现了Iterator接口的对象。
- Iterator对象称为遍历器,用以方便地实现对容器内元素的遍历操作。
- Iterator接口定义了如下方法
- boolean hasNext(); //判断游标右边是否有元素
- Object next();//返回游标右边的元素并将游标移动到下一个位置
- void remove();//删除游标左边的元素,在执行完next之后该操作只能执行一次(因为Iterator只能进行next操作而没有指向上一个元素的操作)
- Iterator对象的remove方法是迭代过程中删除元素唯一安全的方法
如何选择数据结构
Arrayd读快改慢、Linked改快读慢、Hash两者之间
对equals方法和hashcode方法的理解
- override后的equals方法应该通过比较两个对象中的内容来确定两个对象是否相等。
- override后的hashcode方法通过特定的计算方法来计算对象中的hashcode的值。
- 注意:如果hashcode的值会因对象属性的改变而改变,那么则需要十分小心。最好避免这种情况。
- 重写后的equals和hashcode方法应该遵守:如果两个对象equals,hashcode的值一定相等;如果两个对象的hashcode相等,它们不一定equals。
- 判断两个对象是否相等可以:先比较hashcode的值,如果不相等,那么两个对象一定不相等;如果相等,再调用equals方法,如果两个对象equals,那么这两个对象才相等。
Auto-boxing和unboxing
例子
机制
泛型Generic
注意:
- 泛型只在编译阶段有效,下面代码说明,泛型类型实际上还是原来对象所属的类型。
List stringArrayList = new ArrayList();
List integerArrayList = new ArrayList();
Class classStringArrayList = stringArrayList.getClass();
Class classIntegerArrayList = integerArrayList.getClass();
if(classStringArrayList.equals(classIntegerArrayList)){
Log.d("泛型测试","类型相同");
}//输出 D/泛型测试:类型相同
复制代码
流Stream(输入与输出是从程序的角度来讲的)
输入流和输出流
Java所提供的所有流类型都位于java.io包内,且都分别继承以下4个抽象类。
- | 字节流 | 字符流 |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
InputStream
- 继承自InputStream的流都是用于向程序中输入数据的,单位为字节(8bit)。
- 基本方法
- int read() throws IOException;//读取一个字节并以整数(0-255)形式返回
- int read(byte[] buffer) throws IOException;//读取一系列字节存储于一个数组buffer,返回读取字节的个数
- int read(byte[] buffer, int offset, int length);//从offset开始读取length个字节
- void close() throws IOException//关闭流,释放资源
OutputStream
- 继承自OutputStream的流都是用于从程序中输出数据的,单位为字节。
- 基本方法
- void read()
- void read(byte[] buffer)
- void read(byte[] buffer, int offset, int length)
- void close()
- void flush();//将输出流中缓冲的数据全部写到目的地,用于close之前,防止数据还未写完,输出流就被close
Reader
- 以字符为基本单位的输入流。
- 基本方法与InputStream差不多,把byte[] buffer替换为char[] cbuf
Write
- 以字符为基本单位的输出流。
- 基本方法与OutputStream差不多,但是有多两个
- void write(String string);
- void write(String string, int offset, int length)//将字符串写入输出流
- void flush()
节点流和处理流
- 节点流可以从一个特定的数据源(节点)读写数据。如:文件,内存。
- 处理流连接在已存在的流(节点流、处理流)之上,能够进行数据的处理为程序提供更为强大的读写功能。
- 使用方法如下
BufferedWriter bw = new BufferedWriter(Writer w);
//将一个Writer类型的对象作为参数传入
复制代码
转换流
- InputStreamReader和OutputStreamWriter用于字节数据到字符数据之间的转换
- InputStreamReader需要和InputStream“套接”,OutputStreamWriter同理
数据流
- 数据流属于处理流,需要套接在InputStream或OutputStream类型的节点流上,其提供了可以存取**(以字节的方式)**基本类型数据(如int、double等)的方法。即以字节的形式读进去,这样效率高且节约空间。
- 其构造方法为DataInputStream(InputStream in)
- ByteArrayInputStream和ByteArrayOutputStream
示范代码
public static void main(String[] args) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
try {
dos.writeDouble(Math.random());
dos.writeBoolean(true);
ByteArrayInputStream bais =
new ByteArrayInputStream(baos.toByteArray());
DataInputStream dis = new DataInputStream(bais);
System.out.println(dis.readDouble());
System.out.println(dis.readBoolean());
} catch(IOException e) {
e.printStackTrace();
}
}
复制代码
PrintStream和PrintWriter
- PrintStream属于输出流,可以将键盘的输入,输出到指定位置,比如:
PrintStream ps = new PrintStream(new FileOutputStream("c:/..."));
System.setOut(ps);
//从键盘输入的流会通过ps输出到指定文件中
复制代码
Object流
- 用于直接将object写入或读出
- 如果先要将某个类直接写入或读出,则需实现接口Serializable,将其序列化为字节流
- 需要“套接”在OutputStream类对象上
transient关键字
- 被transient关键字修饰的成员变量,在被写入硬盘的时候默认是0或null、false。
GUI Graphics User Interface
Frame类
- 如果要创建窗口,最好自己定义一个窗口类,继承自Frame
Panel类
布局管理器接口LayoutManager
- 实现布局管理器接口的类有:FLowLayout,BorderLayout,GridLayout,CardLayout,GridBagLayout
FlowLayout
new FlowLayout(FLowLayout.RIGHT, 20, 40);
//右对齐,水平间距20像素,行间距40像素
new FlowLayout(FlowLayout.LEFT);
//左对齐,水平间距和行间距默认为5
new FlowLayout();
//居中对齐
复制代码
BorderLayout
- BorderLayout是Frame的默认布局管理器,它将整个容器划分成EAST,WEST,SOUTH,NORTH,CENTER五个区域,component只能被添加到这五个区域(默认添加到CENTER)
- 一个区域只能添加一个component,如果加入多个,原先的会被覆盖
- NORTH,SOUTH这两个区域只能在水平方向上缩放,WEST,EAST只能在垂直方向上缩放,CENTER可以在两个方向上缩放
GridLayout
f.setLayout(new GrideLayout(3,4));
//把f划分为3行4列,共12个一样大的区域
复制代码
注意
- Frame的缺省布局管理器的BorderLayout,Panel的是FlowLayout
- 当把Panel作为一个component添加到某个容器后,Panel仍然可以拥有自己的布局管理器
事件监听
- 事件源对象:发生某些事件的component
- 事件监听器:事件监听器是指实现了某种监听器接口的对象。当事件源对象发生某些事件的时候,会将*事件对象发送给监听器。
- 注册:使某个监听器对象能够监听某个事件源对象,这个行为叫做注册。
- 在事件监听器对象中,想要访问到事件源对象里面的属性,可以使用getSource方法。
TextField文本输入框
//加法运算器
import java.awt.*;
import java.awt.event.*;
public class Test {
public static void main(String[] args) {
new TFFrame().lanuchFrame();
}
}
class TFFrame extends Frame {
TextField num1, num2, num3;
public void lanuchFrame() {
num1 = new TextField(10);
Label l = new Label("+");
num2 = new TextField(10);
Button b1 = new Button("=");
b1.addActionListener(new MyMonitor(this));
num3 = new TextField(11);
setLayout(new FlowLayout());
add(num1);
add(l);
add(num2);
add(b1);
add(num3);
pack();
setVisible(true);
}
}
class MyMonitor implements ActionListener {
TFFrame tf = null;
public MyMonitor(TFFrame f) {
this.tf = f;
}
public void actionPerformed(ActionEvent e) {
int n1 = Integer.parseInt(tf.num1.getText());
int n2 = Integer.parseInt(tf.num2.getText());
tf.num3.setText("" + (n1 + n2));
}
}
复制代码
鼠标适配器
内部类
以上代码可以利用内部类的原理简化,即将MyMonitor类直接在MyFrame类里面声明,这样MyMonitor的成员就可以直接访问MyFrame类的成员变量。
不希望让其他类访问某个类的时候,可以将其定义为内部类
Graphics类
- 每个component都有一个paint(Graphics g)方法用以实现绘图目的,每次重画component的时候都重新调用paint方法