当年万里觅封侯,匹马戍凉州

试题类型:

  • 选择题
  • 读程序写结果
  • 程序填空
  • 编程(2道)
    • 面向对象
    • 图形用户界面,多线程,网络

概述

几个Java技术术语

  • Java虚拟机(JVM) 用软件仿真计算机硬件 实现可移植性
  • Java运行系统(Java运行时系统) 包括JVM的具体实现和Java API
  • Java应用程序编程接口(API) 各种常用类和接口
  • Java开发工具包(JDK) 包含类库、编译运行工具等

Java程序的开发执行流程:

同一个.java文件中可以定义多个类,但是只能定义一个公共类,且文件名称必须和这个公共类名相同

Java语言基础

标识符

定义规则:

  1. 由字母、数字、下划线、$ 组成,不能由数字开头
  2. 不能是Java中的保留字
  3. 大小写敏感,长度无限制

变量

必须先定义再使用,使用标识符表示变量名,变量名标志存放变量值的内存位置,其内存存放的内容是变量的值

Java的变量有两种:局部变量(使用前必须给定初值,否则会编译错误)、类成员变量

变量的类型:

  1. 基本数据类型:
    • 整数类型
    • 实数类型
    • 字符型
    • 布尔型
  2. 构造数据类型:构造类型用类来描述

常量

分为数值常量和符号常量,类静态成员常量只能在定义时初始化

数值常量:

整型:123-15
实型:12.1f
布尔:true
字符:'x'
字符串:"TEST"

符号常量:使用修饰符“final”定义符号常量

final 类型 常量名 = 值;
final int a = 10;

基本数据类型表

数据类型名 占用内存空间
byte 1字节
short 2字节
int 4字节
long 8字节
float 4字节
double 8字节
char 2字节
boolean 1位

整型常量在机器中默认以int类型存储,实型常量在机器中默认以double类型存储,加后缀Ff在机器中以float类型存储

字符类型用来表示单个字符,采用16位二进制Unicode编码表示

布尔型数据只有两个值:truefalse,不可将布尔类型看作整型值

运算符

与c++中一致

5/2=2; 5.0/2.0=2.5
5%2=1; 5.2%2=1.2; 5.2%2.2=0.8
10%-4=2; -10%-4=-2

某个培训中心要为新到的学员安排房间,假设共有x个学员,每个房间可以住6人,用一个公式来计算他们要住的房间数?
(x+5)/6

逻辑运算符:

  • 与:op1 & op2 全真为真
  • 或:op1 | op2 一真即真 对于 & 和 |,两边的表达式任何情况都会参与运算
  • 短路与:op1 && op2 op1为假不计算op2
  • 短路或:op1 || op2 op1为真不计算op2

移位运算符:

使用一个表达式计算2的x次方: 1<<x 将1左移x位 2x

Java中唯一的三元运算符:变量= <布尔表达式> ? <表达式1> : <表达式2>

public class max{
public static void main(String[] args){
int a=3,b=4,c;
c=a>b ? ++a : b++;
System.out.println(a,b,c);
}
}
//输出结果:3 5 4

运算符优先级

()>单目>双目>三目>赋值
双目:算术>关系>逻辑

a=8-2*3<4&&5<2 结果:false

数据类型转换

运算过程中,Java会自动把精度较低的类型转换为精度较高的类型;低精度–>高精度可以自动转换,反之则会出现编译错误,需要强制转换

精度由高到低
double
float
long
int
byte/short/char

自动转换:

'A'+2+2.5   //结果为double类型
'a'+1=98 //char-->int 算数+
"a"+1="a1" //'='两边有一个字符串即为字符串+

强制转换:

int i;byte b;
b=(byte)345; //b=345%256=89
i=(int)(3.8+6); //i=9,强制转换后小数部分被截去

运算时注意(一般的运算都有类型提升功能):

  1. 运算的结果至少是int型,即如果参与运算的两个数级别比int型低或为int型,则结果为int型
  2. 参与运算的数据如果有一个级别比int型高,则运算结果与类型级别高的数相同
  3. 参与运算的两个数据如果类型不一样,会把低级别的数据转换为高级别的类型后再做运算,结果为高级的类型
float x = 3.3f;
double y = 2.9;
byte a = 5;

x+(int)y/3*a
// 结果的值和类型:3.3f

标准输入输出(I/O)

一般用键盘作为标准的输入设备,显示器则是标准的输出设备

System.in 是字节流,作用是从标准输入中读一个字节

  • int read():从流中读取一个字节并将该字节作为整数返回,没有数据则返回-1
  • int read(byte b[]):从流中读取多个字节放到b中,返回实际读取到的字节数
  • int read(byte b[],int off,int len):从流中读取最多len字节的数据, 放到数组b的下标off开始的单元中,返回读取到的字节数
    try{
char ch=(char)System.in.read();
System.out.println(ch);
}catch(IOException e){}
//调用read()函数一定要 try catch

控制语句

switch语句

switch(表达式)
{
case 常量1:语句1 [break;]
case 常量2:语句2 [break;]
……
[dafault:缺省处理语句]
}

for语句:for (表达式1; 表达式2; 表达式3) {}

int a=5,b=6,i=0,j=0;
switch(a)
{
case 5: switch(b)
{
case 5:i++;break;
case 6:j++;break;
default:i++;j++;
} //没有break
case 6: i++;j++;
break;
default: i++;j++;
}
System.out.println(i+","+j);
//结果:1,2

数组

Java中数组是独立的类

一维数组:

  • 定义:int[] a = new int[100];
  • 初始化:int[] b = {1,2,3,4};int[] a = new int[] {1,2,3,4};

Java在对数组元素操作时会对数组下标进行越界检查以保证安全性

每个数组都有一个属性length指明其长度

二维数组:

Java的多维数组实际是数组的数组,不一定是规则的矩阵数组

定义:

对数组的排序

import java.util.Arrays;
Arrays.sort(x);

二分查找(先排序,找到返回下标,没找到返回小于0的数)

int[] x=new int[]{2,5,1,6,8,3};
java.util.Arrays.sort(x);
System.out.println(java.util.Arrays.binarySearch(x,1));

拷贝数组

int[] x;
x = new int[]{3,1,2,4};
int[] y;
y = new int[4];
System.arraycopy(x,0,y,0,4);
//将数组x内的4个元素从下标0开始拷贝到数组y

面向对象程序设计

main()函数写法

public static void main(String[] args) {}

类的定义:

[修饰符] class 类名 [extends 父类名] [implements 接口名列表]
{
[成员变量说明]
[构造方法说明]
[静态初始化说明]
[成员方法说明]
}

类首

[修饰符] class 类名 [extends 父类名] [implements 接口名列表]

访问权限修饰符:
缺省或public
abstract:抽象类(不能创建对象)
final:最终类(不能有子类)

extends:继承(父类)
implements:实现 (接口,可以有多个)

成员变量

[修饰符] 成员变量类型 成员变量名列表;

pubic static int a=10;

大小:public>protected>缺省>private

static–静态变量(类变量),可以通过类访问,也可以通过类的对象访问

没有static修饰的叫做对象变量

final–最终变量(对象常量),说明后不能再改变值,定义时或构造函数中赋值

static final–类常量,一定要在定义时赋值

成员方法

[方法修饰符] 返回值类型 方法名 ([形参列表]) [throws异常列表] {}

publc int max(int a,int b) {return a>b?a:b;}

方法体也可以是一个分号;,表示无具体方法或未实现,当且仅当方法修饰符中有abstractnative时,方法才可无方法体 abstract void play();

方法的重载

类中可以有多个带有不同参数的同名方法,参数列表必须不同

或者参数个数不同,
或者是参数类型不同,
或者参数类型的顺序不同
构造方法

[构造方法修饰符] 方法名 ([形式参数列表]) [throws异常列表] {}

  1. 构造方法的方法名与类名相同
  2. 构造方法没有返回类型,不能写void
  3. 构造方法主要作用时完成对类对象的初始化工作
  4. 每个类至少一个构造方法,没有显式定义构造方法,Java会自动提供一个缺省的构造方法,只要类中显式定义了一个或多个构造方法,而且所有显式定义的构造方法都带参数,那么将失去缺省构造方法

this的使用:this用来表示本类对象

在方法和构造方法中,可以使用this来访问对象的属性和方法

Person(String n,int a){
this.name = n;
this.age = a;
}

static方法中不能使用this

继承

Object类是Java所有类的直接父类或间接父类

子类可以继承父类所有非private的属性和方法(除构造方法)

属性可以继承、添加、隐藏

属性的隐藏(覆盖):子类重新定义一个与父类成员变量完全相同的变量

方法可以继承、添加、覆盖、重载

方法的覆盖:子类中定义的方法和父类中的方法的首部是一样的,包括方法名、参数列表、返回类型和异常抛出,但方法体的实现改变了

方法的重载:方法名相同,但参数列表不同,实际上相当于在子类中新加了一个方法

//某类的静态成员为该类及该类的所有子类所共有
class a
{
public static int b=10;
}
class test extends a
{
public static void main(String args[])
{
test.b=20;
System.out.println(a.b); //20
}
}
//子类中新定义的静态成员变量与父类中的某个静态成员变量同名,则这两个静态成员变量相互独立
super的使用

构造方法不能继承,但是子类的构造方法能确保它的直接父类和间接父类的构造方法都能被调用

使用情况:

  1. 子类隐藏了超类中的变量或方法,而程序中又要使用 super.变量 super.方法([参数表])
  2. 子类的构造方法中引用父类的构造方法 super([参数表])

子类调用父类的构造方法必须放在子类构造方法的第一行

class point{
point(int x,int y){})
}
class color extends point{
color(int x,int y){
super(x,y); //必须放在第一句
}
}

不明确使用super调用父类构造方法时,系统会自动在构造方法中加上super(),来调用父类不带参数的构造方法

建议:在子类的构造方法中最好能明确使用super调用父类的构造方法给从父类继承来的变量初始化

构造方法的调用顺序:

  1. 首先调用父类的构造方法,递归,故最顶级的父类最先调用
  2. 根据各成员的声明顺序,执行成员变量的初始化赋值
  3. 执行自己的构造方法中的语句

子类对象和父类对象的转换:

  1. 子类对象–>父类对象:显式或隐式,子类对象直接向父类对象赋值
  2. 父类对象–>子类对象:只有父类对象实际指向的是一个子类对象时,使用强制类型转换

抽象类

abstract修饰的类和方法,抽象类不能创建任何对象,必须产生子类,由子类创建对象

类中的某一方法是抽象的,整个类就必须说明成抽象的

抽象方法在子类中必须被实现,否则子类仍是抽象的

final类

final类:不能被继承,没有子类

final方法:不能被子类所覆盖

所有final类中的方法默认为final方法

接口

  1. 使程序设计和实现相互分离
  2. 弥补Java只支持单重继承的不足

[修饰符] interface 接口名 [extends] [接口列表] {接口体}

接口的权限修饰符:

  1. 缺省:同包访问
  2. public:任意访问

接口中的成员变量都是隐含public static final的,即静态最终变量(常量)

接口中的方法都是抽象方法,所有方法隐含public abstract

int step = 5; ---> public static final int step =5;

接口的抽象程度比抽象类更高,不需要具体实现优先使用接口

相当于文件夹

import java.awt.*;
import java.awt.event.*;
import java.util.Arrays;

参数传递

Java按值传递所有参数,制作所有参数的副本,不管它们的类型

==!==比较引用型变量时,只能判断运算符两边引用的是否为同一对象,即判断地址值是否相同

判断对象实体值是否相同使用equals()方法

自己定义的类如果要支持equals方法必须要重写从Object类继承来的equals方法

//Object类中的equals方法
public boolean equals(Object obj){
return (this==obj);
}
//重写equals()方法
public boolean equals(Object obj){
if(this==obj) return true;
if(obj==null) return false;
if(getClass()!=obj.getClass()) return false;
Person p = (Person)obj;
if(name.equals(p.name)&&age==p.age) return true;
return false;
}

内部类

将类的定义置于一个用于封装它的类(外部类)中

内部类不能与任何一层外部类同名

作用:逻辑分组,隐藏细节

可以使用protected private修饰符,final abstract static表示不能被继承,不能被实例化,静态内部类

匿名类

没有类名的特殊内部类

当需要创建一个类的对象而且用不上它的名字时,使用内部类可以使代码看上去简洁清楚

没有名字,不能定义构造方法

异常处理

异常处理机制:抛出异常(系统抛出;用户自定义抛出)—>捕获异常(寻找合适的方法处理异常)

格式:

try{
…………
}catch(ExceptionName1 e)
{…………}
catch(ExceptionName2 e) //catch 不一定执行
{…………}
finally //finally 总是执行
{…………}

Exception类子类由两种:

  • 运行时异常:程序编写不正确导致,除数为0、错误的强制类型转换、数组越界访问、空引用
  • 非运行时异常:不是程序本身的错误,如找不到指定的文件

Java程序必须捕获声明抛出所有非运行时异常,对运行时异常不做要求

FileNotFoundException 访问文件未找到,非运行时

IOException I/O故障,非运行时

用户处理异常的三种方法:

  1. try-catch-finally捕获和处理
  2. throws声明抛出
  3. throw定义自己的异常类抛出

将可能抛出一个或者若干个异常的代码放入try语句块中,应尽量减小try代码块的大小

(4)try块中产生了异常,在方法中没有捕获。在这种情况下,Java将执行try块中的代码直到产生异常,然后跳过try块中的代码而转去执行finally子句中的代码,最后将异常抛出给方法的调用者

class J_Test{
public static void main(String[] args){
try{
System.out.print('h');
mb_method1(args);
System.out.print('x');
}catch(Exception e){
System.out.print('m');
}
System.out.print('n');
}
static void mb_method1(String a[]){
try{
mb_method2(a);
System.out.print('a');
}/*catch(Exception e){ //未注释:hbcdxn
System.out.print('b');*/ //注释:hcmn
}
finally{
System.out.print('c');
}
System.out.print('d');
}
static void mb_method2(String a[]){
System.out.println(a[a.length]); //产生数组越界
}
}

Java基本类库

java.lang   //语言包
java.util //工具包
java.io

java.lang.Object 整个类层次结构的根节点

java.lang.Math 提供数学常数及各种函数

  • random随机数
    • 得到一个[0,1)之间的随机数 double c = Math.random();
    • 得到一个[20,80)之间的随机整数 int c = (int)(Math.random()*60+20);
  • ceil 向上取整 floor 向下取整 rint 四舍五入 均为double
  • round 四舍五入 int<--float long<--double

java.lang.Thread 提供对多线程的支持

java.lang.Throwable 所有异常的基类

字符串类

java.lang.String 不可改变的静态字符串

java.lang.StringBuffer 动态可变字符串

String类

所有字符串常量都是String对象,存储在String Pool(字符串池)中,字符串池是常量池的一部分

String对象一旦创建内容不可改变,若要更改,则必须创建一个新的String对象

==比较地址值,equals()比较实体值

public class Test{
public static void main(String[] args){
String a = "hello";
String b = "hello";
System.out.println(a==b); //true 常量池优化

String m = new String("hello");
String n = new String("hello");
System.out.println(m==n); //false 两个对象 两个常量

String a = "hellojava";
String b = "java";
String c = "hello" + b;
System.out.println(a==c) //false a和c不是同一对象

String x = new String("hello");
String y = new String("hello");
System.out.println(x.equals(y)); //true 实体值相同
}
}

常用方法:

String str = "HeLlo";
System.out.println(substring(2)); //字串 Llo
System.out.println(str.charAt(1)); //某个字符 e
System.out.println(str.toUpperCase()); //转为大写 HELLO
System.out.println(str.toLowerCase()); //转为小写 hello
char[] s = str.toCharArray(); //转为字符数组
StringBuffer类

三种构造方法

  1. StringBuffer sb = new StringBuffer();
  2. StringBuffer sb = new StringBuffer(int length());
  3. StringBuffer sb = new StringBuffer(String str);

更新方法:

StringBuffer s = new StringBuffer("hello");
s.append("java"); //hellojava
s.insert(5,"sun"); //hellosunjava
s.setCharAt(1,'E'); //hEllosunjava
s.delect(5,8); //hEllojava

String对象和StringBuffer对象相互转换

StringBuffer sb = new StringBuffer("hello");  //String-->StringBuffer  调用构造方法
String s = sb.toString(); //StringBuffer-->String 使用 toString()方法

向量类

java.util.Vector

数组和向量的不同:

  1. 数组一旦定义,空间长度不可改变,向量空间是动态的
  2. 数组中既能存放基本数据类型,也能存放对象,向量中只能存放对象,可封装类如Integer存放基本数据类型

构造函数

  1. Vector() 默认大小10
  2. Vector(int size) 指定大小
  3. Vector(int size, int inc) 指定大小和增量

创建向量:Vector<Integer> v = new Vector<Integer>(10); <>中的类型不能是基本数据类型

常用方法:

v.add(x);   //添加元素
v.elementAt(idx); //获取下标为idx的元素
v.setElementAt(obj,idx); //修改元素
v.size(); //实际元素个数
v.clear(); //清空向量

图形用户界面

import java.awt.*
import javax.swing.*

JFrame

JFrame类用于创建带有菜单条的全功能对象,为窗口、面板等组件提供框架,可以包含窗口标题、最大化、最小化和关闭窗口等按钮,通常是GUI应用程序窗口的顶层容器组件

JFrame类的对象开始是不可见的,要调用a.setVisible(true)方法

构造方法:

  • JFrame()不带标题的框架
  • JFrame(String)带标题的框架

JFrameJDialog都是Window的子类,他们都是窗口类,默认布局管理器都是BorderLayout

常用方法:

show()  //显示框架
setVisible(boolean b) //使框架可见/不可见(true/false)
setTitle() //设置标题
setSize(int w,int h) //设置框架的尺寸
setBounds(int x,int y,int w,int h) //设置框架的位置及尺寸
add(String p,Component ob) //将组件加入到框架的p位置,没有p默认中心
setLayout(new FlowLayout()) //设置布局管理器

JPanel

面板JPanel是能在屏幕上实际显示的组件,提供容纳其他组件的功能,本身必须放在Window Frame Dialog中才能使用

默认布局管理器是FlowLayout,从左到右,从上到下

设置背景色和前景色:

JPanel b = new JPanel();
b.setBackground(Color.RED); //背景色
b.setForeground(Color.BLUE); //前景色

JButton

构造方法:

  • JButton() 无文本
  • JButton(String t) 有文本

常用方法:

setLable(String t) //设置按钮标志
setText("hello")
addACtionListener(ActionListener 1) //将1指定为按钮的事件监听者

JLabel

构造方法:

  • JLabel() 空标签
  • JLabel(String text) 带有指定文本的标签
  • JLabel(String text, int alignment) 带有指定文本和在容器中的对齐方式的标签

常用方法:

setText(String text)  //设置文本 
setAlignment(int alignment) //设置对齐方式 JLabel.LEFT/CENTER/RIGHT

JTextField

构造方法:

  • JTextField() 空文本框
  • JTextField(String text) 有初始文本
  • JTextField(int Columns) 指定列数
  • JTextField(String text, int Columns) 初始文本、指定列数

常用方法:

setText(String s)  //设置文本框中的字符串
getText(String s) //获得文本框中的字符串
addActionListener(ActionListener 1) //指定1为文本框的事件监听者
setEchoChar(String s) //设置用户输入的回应字符,输入密码时可设置为*

事件处理

见本文末尾实例

Window关闭窗体

f.addWindowListener(new windowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});

图形绘制

见本文末尾实例

多线程

实现方式:

  1. 继承Thread,覆盖run()方法

    class mythread extends Thread{
    public void run()
    {………}
    }
  2. 实现Runnable,实现run()方法

    class mythread implements Runnable{
    public void run()
    {………}
    }

两个线程,一个线程让标签1向右移动,另一个线程让标签2向下移动,主界面设置按钮,启动线程

import javax.swing.*;
import java.awt.*;
import java.util.*;
public mythread extends Thread{
JLabel j1,j2;
mythread(JLabel j1,Jlabel j2){
this.j1 = j1;
this.j2 = j2;
}
public void run(){
try{
sleep(1000);
j1.setLocation(j1.getX()+10,j1.getY());
j2.setLocation(j1.getX(),j1.getY()+10);
}catch(InterruptedException e){System.out.println(e.toString());}
}
}
public class Test extends JFrame{
public static void main(String[] args){
Test f = new Test();
f.setTitle("thread");
f.setVisible(true);
Jlabel j1 = new JLabel("label1");
Jlabel j2 = new JLabel("label2");
f.add(j1);
f.add(j2);
JButton b = new JButton("start");
f.add(b);
b.addActionListener(new actionListener(){
public void actionPerformed(ActionEvent e){
mythread t1 = new mythread(j1,j2);
mythread t2 = new mythread(j1,j2);
t1.start();
t2.start();
}
});
}
}

线程生命周期

  1. 创建状态:Thread myThread = new MyThreadClass();
  2. 可运行状态:分配资源
  3. 不可运行状态:
    • 调用sleep()方法 –> 等待
    • 调用suspend()方法 –>调用resume()方法
    • 调用wait()方法 –>调用notifyAll()方法
    • 输入输出流发生阻塞 –>等待
    • 线程试图调用另一个对象的同步方法 –>等待释放同步锁
  4. 死亡状态:
    • 自然撤销
    • 调用stop()方法停止当前线程 ,一般不用

同步与互斥

Java中只需要把一个方法声明为synchronized即可有效防止冲突

public synchronized void method(){}
wait和notify

wait导致当前线程等待,直到另一个线程调用该对象的notify()方法

notify唤醒正在等待对象监视器的单个线程

waitnotify必须配合synchronized使用,waitnotify前用

网络编程

基于TCP的C/S通信

一些实例

输入10个数并排序

import java.util.*;
public class Test{
public static void main(String[] args){
int[] a = new int[10];
Scanner scan = new Scanner(System.in);
for(int i = 0;i < 10;i++){
a[i] = scan.nextInt();
}
Arrays.sort(a);
for(int i = 0;i < 10;i++){
System.out.print(a[i]+" ");
}
}
}

复数类

import java.util.*;
public class Complex{
public int realPart;
public int maginPart;
public Complex(){
this.realPart = 0;
this.maginPart = 0;
}
public Complex(int r,int i){
this.realPart = r;
this.maginPart = i;
}
public String toString(){
return this.realPart+"+"+this.maginPart+"i";
}
public static Complex complexAdd(Complex a){
return new Complex(this.realPart + a.realPart,this.maginPart + a.maginPart);
}
public static Complex complexSub(Complex a){
return new Complex(this.realPart - a.realPart,this.maginPart - a.maginPart);
}
public static void main(String[] args){
Scanner scan = new Scanner(System.in);
Complex a1 = new Complex(scan.nextInt,scan.nextInt);
Complex a2 = new Complex(scan.nextInt,scan.nextInt);
System.out.println("a1:"+a1.toString());
System.out.println("a2:"+a2.toString());
System.out.println("a1+a2="+a1.Add(a2).toString());
System.out.println("a1-a2="+a1.Sub(a2).toString());
}
}

加法器

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class jiafaqi extends JFrame{
public static void main(String[] args){
jiafaqi j = new jiafaqi();
j.setTitle("加法器");
JTextField shu1 = new JTextField(5);
JTextField shu2 = new JTextField(5);
JTextField result = new JTexField(5);
JButton jia = new JButton("+");
JButton jian = new JButton("-");
j.add(shu1); //添加组件
j.add(shu2);
j.add(jia);
j.add(jian);
j.add(result);
j.setLocation(300,300);
j.setSize(500,100); //事件监听器 匿名类
jia.addActionListener(new ActionListener(){
public void actionPeformed(ActionEvent e){
int x = Integer.parseInt(shu1.getText());
int y = Integer.parseInt(shu2.getText());
int z = x + y;
result.setText(Integer.toString(z));
}
});
jian.addActionListener(new ActionListener(){
public void actionPeformed(ActionEvent e){
int x = Integer.parseInt(shu1.getText());
int y = Integer.parseInt(shu2.getText());
int z = x - y;
result.serText(Integer.toString(z));
}
});
f.setVisible(true); //别忘了这个
}
}

变脸

利用事件处理程序mouseUp()实现程序运行后出现一张笑脸,鼠标点击一次则变成哭脸,再点击一次又变成笑脸,依次轮换

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Test extends JFrame{
static int m = 0;
public static void main(String[] args){
Test f = new Test();
f.setTitle("变脸");
f.setSize(300,300);
f.setVisible(true);
f.addMouseListener(new MouseAdapter(){ //鼠标的点击事件
public void mouseClicked(MouseEvent e){
f.reprint();
}
});
}
public void paint(Graphics g){
if(m++%2==1){
super.paint(g); //消除之前画的
g.getColor(Color.blue);
g.drawString("哭!",80,60);
g.drawOval(100,50,120,160);
g.drawArc(170,90,30,30,0,-180);
g.drawArc(120,90,30,30,0,-180);
g.drawArc(120,150,80,80,20,140);
}
else{
super.paint(g); //消除之前画的
g.getColor(Color.blue);
g.drawString("笑!",80,60);
g.drawOval(100,50,120,160);
g.drawArc(170,90,30,30,0,180);
g.drawArc(120,90,30,30,0,180);
g.drawArc(120,150,80,80,-20,-140);
}
}
}

GUI多线程

编写一个图形用户界面程序,窗体的宽度300,高度150,布局管理器为null,窗体上有二个标签和二个按钮,标签的位置为(10,30)和(200,60),按钮的位置为(50,100)和(150,100),它们的宽度和高度都是80和20。编写一个线程,该线程可以让标签向右或向左移动10次,每次移动10个单位,间隔1秒,通过按钮的动作事件启动上述线程,“向右走”按钮启动“向右移标签”,“向左走”按钮启动“向左移标签

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Test extends Thread{
JLabel l1,l2;
static boolean bool;
public Test(JLabel l1,Jlabel l2){
this.l1 = l1;
this.l2 = l2;
}
public void run(){
if(bool==true){
try{
for(int i=0;i<10;i++){
l1.setBounds(l1.getX()+10,30,80,80);
Thread.sleep(1000);
}
}catch(Exception e){System.out.println(e.toString());}
}
else{
try{
for(int i=0;i<10;i++){
l1.setBounds(l2.getX()-10,60,80,80);
Thread.sleep(1000);
}
}catch(Exception e){System.out.println(e.toString());}
}
}
public static void main(String[] args){
JFrame f = new JFrame();
f.setSize(300,200);
f.setVisible(true);
f.setLayout(null);
JLabel l1 = new JLabel("右移");
JLabel l2 = new JLabel("左移");
l1.setBounds(10,30,80,20);
l2.setBounds(200,60,80,20);
f.add(l1);
f.add(l2);
JButton b1 = new JButton("右");
JButton b2 = new JButton("左");
b1.setBounds(50,100,80,20);
b2.setBounds(150,100,80,20);
f.add(b1);
f.add(b2);
Test t1 = new Test(l1,l2);
Test t2 = new Test(l1,l2);
b1.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
bool = true;
t1.start();
}
});
b2.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
bool = false;
t2.start();
}
});
}
}