环境变量配置:PATH、CLASSPATH(类路径)
main 方法是一个特殊的方法, 每个 java 应用程序都需要含有这个方法, 因为它是程序执行的入口, 由它再去调用其他方法
main 方法必须放在类中, 而且格式固定:
public static void main(String[] args)
或
public static void main(String args[])
Java 区分大小写
同一个 .java 文件中可以定义多个类, 但是只能定义一个公共类, 且文件名必须和公共类相同
只能有一个公共类,但不是必须有公共类
main()不一定放在公共类中,但是命令行运行的是main()所在的类。
考点:
//
单行注释: 表示从此向后,直到行尾都是注释
/*……*/
块注释: 在“/”和“/”之间都是注释
/**……*/
文档注释: 所有在/**
和*/
之间的内容可以用来自动形成文档——javadoc
两种变量:局部变量、类成员变量,均需要先定义后使用。
局部变量需要赋值才能使用,类成员变量不需要。因为局部变量没有默认值,而类成员变量会默认初始化。
变量名区分大小写,使用驼峰命名法。
(1)数值常量
(2)符号常量:使用修饰符final
定义符号常量,常量的值一旦确定不可更改。
final int a=10;
System.out.println(a);
final int a;
a=10;
System.out.println(a);
类静态成员常量只能在定义时初始化;方法中的常量(局部常量)可以在定义时初始化,也可以先定义,以后再初始化。
(1)整型(int、short、long、byte)
十进制:42
,八进制:052
,十六进制:0x2A、0X2a
整型常量默认以int
类存储,后面加上L
或l
,则以long
类型存储
(2)实型(float、double)
实型常量默认以double
类型存储,后面加上F
或f
则以float
类型存储。
十进制:-3.5f 、0.0f 、123.45f 、+678.9f
,采用十进制表示法时,小数点的两侧都必须有数字, 缺一不可。
科学表示法: <尾数> E <阶码 >
,-1.234567E+12
(3)布尔型(boolean)
布尔型只有true
和false
,Java中不可将布尔类型看做整型值。
(4)字符型(char)
表示单个字符,采用16位二进制 Unicode 编码表示(2字节),
字符常量是用两个单引号括起来的一个字符,也可用unicode编码表示一个字符常量,如\u0041
(1)自增、自减
a=5
++a + 10 = 16, a = 6
a++ + 10 = 15, a = 6
--a + 10 = 14, a = 4
a-- + 10 = 15, a = 4
(2)如果整数相除,则结果取整;如果浮点数相除,则是通常意义上的除法,如5.0/2.0结果为2.5
(3)关系运算符(== ,!= ,< ,<= , > ,>= , instanceof
)
instanceof: 用来确定一对象是否是某一指定类的对象
class Demo {
public static void main(String args[]) {
Demo t = new Demo();
if (t instanceof Demo)
System.out.println("是");
}
}
int a=7,c; //a= 00000000000000000000000000000111
c = a>>3; //c=00000000000000000000000000000000=0
c = a << 3; //c=00000000000000000000000000111000=56
c = a >>> 3;//c=00000000000000000000000000000000=0
int a=-8;
System.out.println(a>>>1); //结果2147483644
int i=88>>32;
System.out.println(i); //结果88
在进行移位之前,java系统首先把移的位数与被移位的位数求余数,然后移动这个位数
问:如何用一个表达式计算2的X次方?
答:1 << x
问:如何获取一个整数的第4个比特(从低位算起)?
答:(x & (1<<3))>> 3
(6)赋值运算符
(1)优先级
(2)结合性
例子:a=8 – 2 * 3 <4 && 5 < 2
,结果为false
b=(byte)345; //b为345%256=89
i=(int)(3.8+6); //强制转换后小数部分被截去,i得到9
运算时注意(一般的运算都有类型提升功能):
(3)隐含强制类型转换
byte b=123;//合法
short s=123;//合法
b=b+3; //不合法
int i=123;
byte b=i; //不合法,正确的做法是byte b=(byte)i;
byte a = 1;
byte c = (byte)(a + b); //合法
(4)练习:
'A'+2+2.5
为double类型
int x=1; float y=3.5f;
,则 x+(int)y*2
值为7,为int类型
char a='a'
,则 a + 1
为98,int类型
(5)若运算符两边有字符串类型(双引号),则+
为字符串连接符。
"a" +1 结果为"a1"
"a"+1+1 结果为"a11"
"a"+(1+1) 结果为"a2"
System.in是字节流,作用是从标准输入读一个字节。
read() 方法返回值是 int 类型!
注意:调用 read() 函数一定要 try catch,且为IOException
try{
char ch=(char)System.in.read();
System.out.println(ch);
}catch(IOException e){}
}
从键盘读一数字串或一个整数:
import java.io.*;
class ReadStringOrInt{
public static void main(String args[]){
byte buf[]=new byte[20];
String str;
int anInt;
try{
System.in.read(buf);
str=new String(buf);
anInt=Integer.parseInt(str.trim());
}catch(Exception e){ }
}
}
Java中,数组是独立的类,有自身的方法,不只是变量的集合。
数组作为函数参数传入,形参的值变化,实参也会变化。
public class test {
public static void main(String[] args) {
int[] a = new int[] { 1, 2, 3 };
System.out.println("Outside1: " + a[0]);
test(a);
System.out.println("Outside2: " + a[0]);
}
static void test(int[] a) {
a[0] = 0;
System.out.println("Inside: " + a[0]);
}
}
上述程序输出:
Outside1: 1
Inside: 0
Outside2: 0
(1)一维数组
一维数组的声明:
int list[ ];
int[] list;
一维数组的初始化:
int[] a={1,2,3,4}
int[] a=new int[4];
a[0]=1;a[1]=2;a[2]=3;a[3]=4
int[] a=new int[]{1,2,3,4};
int[] a;
a=new int[]{1,2,3,4};
Java 在对数组元素操作时会对数组下标进行越界检查,以保证安全性。
int[] arr = {1,2,3,4};
System.out.println(arr[4]);
会抛出异常:java.lang.ArrayIndexOutOfBoundsException
数组可调用成员变量 length
查看其长度。
int[] arr = {1,2,3,4};
System.out.println(arr.length); //输出4
(2)二维数组
二维数组为一个特殊的一维数组,其每个元素又是一个一维数组。
二维数组的声明:
int intArray[ ][ ];
int[ ][ ] intArray;
(3)数组相关函数(java.util.Arrays)
Arrays.sort()
对数组x内的元素进行排序(升序)Arrays.binarySearch(x,1)
二分查找,在数组x中查找1,输出0;如果没找到,则会输出一个<0的数Ayyars.fill()
填充数组System.arraycopy()
拷贝数组考点:全是重点
(1)封装
(2)继承
(3)多态:指程序中相同名字表示不同含义的情况。
(4)类首说明
[修饰符] class 类名 [extends父类名] [implements接口名列表]
定义在成员函数中的变量只是局部变量,不是成员变量。类的成员变量和类中的局部变量可以重名。
大小:public >protected >缺省>private
注意: 在main方法中,不管是本类还是非本类,要访问实例变量都要创建对象,可以引申到其他所有的类方法(静态方法) 中
静态变量也叫类变量,可以用类访问,也可以用该类的对象访问。
形式:类名.静态成员变量
或 对象名.静态成员变量
类常量一定要在定义时就给定初始值;对象常量可以先定义,然后在每一个构造函数中进行赋值
static final int x = 5;
//static final int x; x = 5; //Wrong!
方法体也可以是一个分号“;”,表示无具体方法(方法还没有实现,即只是一个方法框架。当且仅当方法的修饰符中有abstract
或native
时,方法才可无方法体。
abstract void play();
类方法是对整个类而言的,而不是针对类的对象,方法体中不能有与对象有关的内容。
含义:类中定义多个带有不同参数的同名方法,是实现多态性的方法之一。
规则:多个方法有相同的名字,但是这些方法的参数列表必须不同(包括参数个数不同、参数类型不同、参数类型的顺序不同)
仅返回值类型不同不能实现重载
除了同一个类,方法的重载也可以在父类和子类之间
this的含义:
在所有的非static方法中,都隐含了一个参数this。而static方法中,不能使用this。
Object 类是 Java 中所有类的直接或间接父类。
子类可以继承父类所有非 private 属性及方法(构造函数不被继承)
属性的隐藏:子类可以定义与父类相同名字的属性,称为属性的隐藏
方法的覆盖:子类可以定义与父类中的方法具有相同首部的方法(包括方法名、参数列表、返回类型和异常抛出),称为方法的覆盖。
方法的重载:方法名相同,但参数列表不同。实际是相当于在子类中新加了一个方法。
被覆盖和重载的方法均不能为private。
某类的静态成员为该类及该类的所有子类所共有
如果子类中新定义的静态成员变量与父类中的某个静态成员变量同名,则这两个静态成员变量相互独立(可以使用类名进行调用)
不允许在子类中降低成员(包括变量和方法)的访问权限
super代表父类对象,在继承中有重要的作用
两种使用情况:
① 子类隐藏了超类中的变量或方法,而在程序中又要使用超类中被隐藏的变量或方法时
格式:super.变量 ; super.方法([参数表])
class Country
{
String name;
void value(){ name="China"; }
}
public class City extends Country
{
String name;
void value()
{
name="Hefei";
//调用同名的方法
super.value();
System.out.println(name);
System.out.println(this.name);//调用同名的成员变量
System.out.println(super.name);
}
public static void main(String args[])
{
City c=new City();
c.value();
}
}
运行输出:
Hefei
Hefei
China
② 在子类的构造方法中引用超类的构造方法时
格式: super([参数表])
在构造方法中使用super时,super语句必须放在第一句
建议:在子类的构造方法中最好能明确使用super调用父类的构造方法给从父类继承来的变量初始化
不明确的使用super构造父类构造方法可能会出错(当父类中没有不含参的构造函数时)
构造方法调用顺序:
一个复杂对象的构造方法调用顺序如下:
① 首先调用父类的构造方法(递归,也就是说,最顶级的父类会最先调用)。类的实例对象之间可以相互进行类型转换,分为:
例子:
class A
{String s = "A"}
class B extends A
{String s = "B";}
public class test{
public static void main(String[] args){
A a1 = new A();
B b1 = new B();
A a3 = b1; //合法,子类对象转父类对象
A a2 = new B();
B b3 = (B)a2; //合法,强制类型转换
//B b4 = (B)a1 //不合法,父类对象指向的不是子类对象
}
}
final类:类被 final 修饰,说明它是最终类,不能被继承。
final方法:方法被 final 修饰,说明它是最终方法,不能被覆盖(重写)。
注意:所有包含在 final 类中的方法,都被默认为是 final 的。因为这些方法不可能被子类所继承,所以不可能被重载,自然都是最终的方法。
接口作用
接口的权限修饰符有两种:
接口可以多继承(使用extends继承其他接口),接口中的方法都是抽象的。
接口的说明:
[修饰符] interface 接口名[extends] [接口列表]
{
接口体
}
例如,在接口体中int STEP=5;
等同于public static final int STEP=5;
[类修饰符] class类名 [extends子句] [ implements 子句]
在implements子句中可以包含多个接口类型,各个接口类型之间用逗号隔开
利用接口实现多重继承:
…
本身是一种命名机制(防止同名的类发生冲突),具体的表现就是一个文件夹
package 包名;
import package1[.package2…].(classname|*);
比较两个变量是否是同个变量(引用值相等):== 和 !=。
比较两个变量的内容是否相等,用 equals() 方法。
自己定义的类要实现比较内容,则必须重写 equals() 方法:
public boolean equals(Object obj) {
if(obj == null) return false;
if(this == obj) return true;
if(getClass() != obj.getClass()) return false;
Person p = (Person)obj;
if(name.equals(p.name) && age == p.age) return true;
return false;
}
考点:会些图形用户编程中的事件处理
定义:类或方法中定义的一种没有类名的特殊内部类。
作用:当需要创建一个类的对象而且用不上它的名字时,使用内部类可以使代码看上去简洁清楚。
类中不能定义构造方法,因为它没有名字。
考点:
(1) 运行时异常
RuntimeExceptiontion类及其所有子类。运行时异常时程序员编写程序不正确所导致的异常。理论上,程序员可以通过检查和测试查出制类错误。
如除数为零等,错误的强制类型转换、数组越界访问、空引用。
(2)非运行时异常(一般异常)
指可以由编译器在编译时检测到的、可能会发生在方法执行过程中的异常,如找不到指定的文件等,这不是程序本身的错误,如果这些异常情况没有发生,程序本身仍然是完好的。
注意:编译器强制要求Java程序必须捕获或声明抛出所有非运行时异常,但对运行时异常不作要求。
可以用try-catch-finally语句进行捕获和处理
(1)try语句
(2)catch语句
(3)finally语句
try{
//调用可能产生异常的方法及其它java语句
}
catch(异常类名1 异常对象名e){
//异常处理语句块
}
catch(异常类名2 异常对象名e){
//异常处理语句块
}
finally{
//最终处理
}
声明抛出异常:不捕获异常,而是将异常交由上一层处理,在其他地方捕获异常
带throws异常说明的方法说明形式如下:
... 方法名(...)[throws 异常类列表]
{方法体}
例:
class Test {
public String getInput() throws IOException {
System.in.read();
return null;
}
}
注意:
(1)在捕获一个异常前,必须有一段Java代码来生成和抛出一个异常对象。
Java也可以用throw语句抛出异常,格式如下:
throw ThrowableObject;
(2)使用throw语句应注意:
(3)抛出异常三步骤:
①确定异常类
②创建异常类的实例
③抛出异常
import java.io.IOException;
public class ThrowTest {
static String getInput() throws IOException { //throws声明抛出异常
char[] buffer = new char[20];
int counter = 0;
boolean flag = true;
while (flag) {
buffer[counter] = (char) System.in.read();
if (buffer[counter] == '\n')
flag = false;
counter++;
if (counter >= 20) {
//throw抛出异常
throw new IOException("buffer is full");
}
}
return new String(buffer);
}
public static void main(String[] args) {
//try-catch语句捕获异常
try {
System.out.println(getInput());
} catch (IOException e) {
e.printStackTrace();
}
}
}
习题: 当下面的程序的输入是“1 2 3 4”时,程序的输出是什么,如果把红色的语句去掉,输出是什么?
public class J_Test {
public static void main(String args[]) {
try {
mb_method1(args); //1
} catch (Exception e) { //在method1里捕获了异常,这里不再捕获
System.out.print('m');
}
System.out.print('n'); //7.输出 n
}
static void mb_method1(String a[]) {
try {
mb_method2(a); //2
System.out.print('a');
} catch (Exception e) {
System.out.print('b'); //4.输出 b
} finally {
System.out.print('c'); //5.输出c
}
System.out.print("d"); //6.输出 d
}
static void mb_method2(String a[]) {
System.out.println(a[a.length]); //3.数组越界异常
}
}
上述程序输出:bcdn
若去掉mb_method1中的catch语句:
public class J_Test {
public static void main(String args[]) {
try {
mb_method1(args); //1
} catch (Exception e) { //method1中有未捕获的异常,此处捕获
System.out.print('m'); //5.输出m
}
System.out.print('n'); //6.输出n
}
static void mb_method1(String a[]) {
try {
mb_method2(a); //2
System.out.print('a');
} finally {
System.out.print('c'); //4.输出c,但未捕获异常
}
System.out.print("d");
}
static void mb_method2(String a[]) {
System.out.println(a[a.length]); //3.数组越界异常
}
}
输出:cmn
考点:
(1)String类的所有方法都不会改变String类对象内容,要改变String类对象的值就必须创建一个新的String对象
String a = "hello";
System.out.println(a);
String a="hello";
String b=new String("java"); //实际上创建了两个对象
(2)String是类,在比较字符串内容时,不能用==
,而应该用equals
方法。String类覆盖了Object类的equals方法
(3)Java为节省内存空间、提高运行效率,编译时将String Pool中所有相同的字符串合并,只占用一个空间。导致引用变量a和b指向同一个对象,用==比较a和b,一定是相等的
String a="hello";
String b="hello";
if(a==b) {
System.out.println("相等");
}else{
System.out.println("不等"); }
//输出结果:相等
由于java是在编译时将StringPool中所有相同的字符串合并,所以如下程序,并未将a指向的字符串与c指向的字符串合并,导致a和c指向的不是同一个对象。
String a="hellojava";
String b="java";
String c="hello"+b;
if(a==c){
System.out.println("相等");
}else{
System.out.println("不等");
}
//输出结果:不等
(4)String对象作为参数传递和基本数据类型效果一样,因为它是不可改变的字符串,即形参变化不会引起实参的变化。
(5)常用字符串方法
求子串(字符串可看做一串字符,第一个字符下标为0):
String a="hello";
String b=a.substring(0,4);//得到“hell”
String c=a.substring(2,3);//得到“l”
求字符串中字符的个数(length函数):
String a="hello";
int b=a.length();//得到5
得到字符串中的某个字符(charAt函数):
String a ="hello";
char b =a.charAt(0);//得到下标为0的字符h
字符数组转换为String:
char[] a = {'a','b','c','d'};
String b = new String(a);
String转换为字符数组:
String a = "hello";
char[] b = a.toCharArray();
字节数组转换为String:
byte [] a={65,66,67,68};
String b=new String(a);//得到ABCD
大小写转换:
String s1="Hello";
String s2=s1.toUpperCase();//得到“HELLO”
String s3=s1.toLowerCase();//得到“hello”
线程安全的可变字符序列
(1)三种构造方法:
//构造一个其中不带字符的字符串缓冲区,其初始容量为 16 个字符
StringBuffer sb = new StringBuffer();
//构造一个不带字符,但具有指定初始容量的字符串缓冲区
StringBuffer sb = new StringBuffer(int capacity);
//构造一个字符串缓冲区,并将其内容初始化为指定的字符串内容
StringBuffer sb = new StringBuffer(String str);
(2)更新方法
StringBuffer s = new StringBuffer("hello");
//添加
s.append("java"); //hellojava
//插入
s.insert(5, "sun"); //hellosunjava
//修改
s.setCharAt(0, 'H'); //Hellosunjava
//删除
s.delete(5, 8); //Hellojava
(3)String 对象和 StringBuffer 对象相互转换:
//String转StringBuffer
StringBuffer sb = new StringBuffer("hello");
//StringBuffer转String
String s =sb.toString();
(4)与String类不同,StringBuffer类的对象作为参数传入时,形参的改变会引起实参的改变。如下例:
(5)利用StringBuffer类将键盘输入的数据建立一个字符串实例
import java.io.IOException;
public class StringBufferToString {
public static void main(String[] args) {
char ch;
try {
int length = 20;
StringBuffer strb = new StringBuffer(length);
while ((ch = (char) System.in.read()) != '\n') {
strb.append(ch);
}
String str = strb.toString();
System.out.println(str);
} catch (IOException e) {
e.printStackTrace();
}
}
}
//将字符串转换为int型
String s = "1234";
int i = Integer.parseInt(s);
//将int型转换为字符串
int i=1234;
String s=Integer.toString(i);
float f=Float.parseFloat(s); //转成单精度数
double d=Double.parseDouble(s);
其他Double, Float等数据类型类以此类推
//得到一个[0,1)之间的随机数
double c = Math.random();
//获取20~80之间的随机数
(int)(Math.random()*60+20)
或
(int)(Math.random()*60)+20
//返回x的y次方
double a = Math.pow(2, 4);
//返回x的平方根
double a = Math.sqrt(4);
(1)Vector
(2)向量Vector与数组Arrays的异同
相同点:
不同点:
(3)构造函数
//使用指定的初始容量和容量增量构造一个空的向量
Vector(int capacity, int capacityIncrement);
Vector(int capacity);
Vector();
(4)创建向量
Vector<元素类型> 向量名称 = new Vector<元素类型>(容量);
//这里元素类型不能是基本数据类型
Vector<String> v = new Vector<String>(5);
(5)重要方法:
v.add(x); //添加元素
v.elementAt(idx); //获取下标为idx的元素
System.out.println(v.size()); //元素个数
System.out.println(v.capacity()); //向量容量
v.insertElementAt(obj, idx); //在下标为idx的位置插入obj
v.setElement(obj, idx); //修改元素
v.removeElementAt(idx); //删除元素
v.clear(); //清空向量
v.contains(obj); //判断是否包含元素obj
v.indexOf(obj); //返回向量中obj的下标,若无,返回-1
(6)Vector的初始大小为10,在自动扩充时,如果没有指定每次增长的大小,则默认是翻倍增长
考点:
I/O操作注意要用try…catch…捕获异常
字节流: 以字节作为基本单位进行读写
字符流: 对以字符作为基本单位的数据源或者数据目的进行读写
标准输入输出流都是字节流(System.in、System.out), 可以通过InputStreamReader
和OutputStreamWriter
转换为字符流:
InputStreamReader isr = new InputStreamReader(System.in);
char c = (char)isr.read();
System.out.println(c);
File f1 = new File("G:\\java-example\\myfilel.txt");
File f2 = new File ("G:\\java", "myfile2.txt");
File f3 = new File ("myfile3.txt");
FileInputStream
和FileOutputStream
的数据源都是文件,用于进行文件输入输出的处理。
(1)FileInputStream
FileInputStream:封装了从文件中读取字节的功能,该类是用来读取字节文件的,如图像文件,如果读取字符或者文本文件,则最好使用FileReader类。
FileInputStream fis = new FileInputSteam("a.jpg");
File file = new File("b.jpg");
FileInputStream fs = new FileInputStream(file);
(2)FileOutputStream
构造方法:
FileOutputStream(File file)
FileOutputStream(File file, boolean append)
FileOutputStream(FileDescriptor fdObj)
FileOutputStream(String name)
FileOutputStream(String name, boolean append)
写入字节的方法:
void write(byte[] b)
void write(byte[] b, int off, int len)
void write(int b)
例子:
//BufferedInputStream
FileInputStream fis=new FileInputStream("text");
BufferedInputStream bis=new BufferedInputStream(fis);
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("text"));
//BufferedReader
new BufferedReader(new InputStreamReader(new FileInputStream("demo.txt"),"gbk"));
(1)FileReader和FileWriter
用于字符文件的输入输出处理,是专门读取和输出字符(文本)文件的类。
//FileReader
File f=new File("d:\\t1.txt");
FileReader f1=new FileReader(f);
FileReader f2=new FileReader("d:\\t1.txt");
//方法
read( )
read(char b[ ])
read(char b[ ],int off,int len)
close()
//FileWriter
File f=new File("d:\\t1.txt");
FileWriter f1=new FileWriter(f);
FileWriter f2=new FileWriter("d:\\t1.txt");
//方法
write(char c)
write(char b[ ])
write(char b[], int off, int len)
close()
//完后一定要关闭输出流,数据才真正地写到了文件中!
将字节流转字符流从文件中读取数据:
import java.io.*;
public class FileReaderDemo {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("demo.txt"), "gbk"));
String s;
//readline()到达流末尾,就返回null
while ((s = br.readLine()) != null) {
System.out.println(s);
}
//char[] buff = new char[1024];
//int len = 0;
//while ((len = br.read(buff)) != -1) {
//System.out.println(new String(buff, 0, len));
//}
br.close();
}
}
所以字节流转字符流即一层层封装:
new FileInputStream("demo.txt"); => 字节流
new InputStreamReader(new FileInputStream("demo.txt"), "gbk"); => 封装为字符流
new BufferedReader(new InputStreamReader(new FileInputStream("demo.txt"),"gbk")); => 用BufferedReader封装
BufferedReader对象有readline()方法读取一行
考点:
创建简单窗体程序
面板和窗体默认布局管理器
如何设置窗体和组件位置、大小、背景色、前景色(函数使用)
掌握两种布局管理器 FlowLayout BoardLayout
组件:按钮、文本框、标签
事件处理
画图(继承),记住方法
1、JFrame
通常是GUI应用程序的顶级容器组件,默认布局方式为BorderLayout
构造方法:
JFrame()
JFrame(String title)
常用方法:
setVisible(boolean b) //设置窗体是否可见(一定要写)
setSize(int width, int heidht) //设置窗体大小
setLocation(int x, int y) //设置窗体位置,(x,y)为左上角的坐标,横轴x,数轴y
setBounds(int x,int y,int width, int heidht) //同时设置位置和大小
setLayout(LayoutManager manage) //设置布局方式,如setLayout(new FlowLayout())
add(Component ob) //把其他组件ob加到窗体中
2、JDialog
1、Java实现多线程两个方式:
(1)声明一个Thread类的子类,并覆盖run()方法
import java.util.*;
public class TimePrinter extends Thread {
int pauseTime;
String name;
public TimePrinter(int x, String n) {
pauseTime = x;
name = n;
}
public void run() {
while(true) {
try {
System.out.println(name + ":" + new
Date(System.currentTimeMillis()));
Thread.sleep(pauseTime);
}catch(Exception e) {
System.out.println(e);
}
}
}
public static void main(String[] args) {
TimePrinter tp1 = new TimePrinter(1000, "Fast Guy");
tp1.start();
TimePrinter tp2 = new TimePrinter(3000, "Slow Guy");
tp2.start();
}
}
但是当类已经有了其他的直接继承父类,如JFrame,此时就可以使用下面一种方法。
(2)声明一个实现Runnable接口的类,并实现run()方法
import java.util.*;
public class TimePrinterDemo implements Runnable {
int pauseTime;
String name;
public TimePrinterDemo(int x, String n) {
pauseTime = x;
name = n;
}
public void run() {
while (true) {
try {
System.out.println(name + ":" + new Date(System.currentTimeMillis()));
Thread.sleep(pauseTime);
} catch (Exception e) {
System.out.println(e);
}
}
}
//加上主线程共3个线程
public static void main(String[] args) {
//还是需要封装在Thread中创建线程,然后使用Thread的start()方法启动线程
Thread t1 = new Thread(new TimePrinterDemo(1000, "Fast Guy"));
t1.start();
Thread t2 = new Thread(new TimePrinterDemo(3000, "Slow Guy"));
t2.start();
}
}
注意: 使用第二种方法时,在创建线程时还是用Thread类创建线程对象,把实现Runnable接口的类的对象作为Thread类的构造方法的参数,再调用Thread类对象的start()方法
(2)Thread类常用构造方法
public Thread()
public Thread(Runnable target)
(3)Thread类常用方法
注意:如果要用Thread.sleep()函数,一定要放在try...catch...
中
try{
Thread.sleep(1000);
}catch (Exception e){
System.out.println(e);
}
解决共享资源的访问冲突问题:只需要把一个方法声明为synchronized
,便可有效地防止冲突.
Java中每个对象都包含了一把锁(也叫“监视器”),它自动成为对象的一部分.调用任何synchronized方法时,对象就会被锁定,不可调用那个对象的其他任何synchronized方法
两种方式:
① 同步函数:
class Bank{
private int totalNum = 0;
public synchronized void add(int num) {
totalNum += num;
System.out.println("totalNum=" + totalNum);
}
}
② 同步代码块
class Bank{
private int totalNum = 0;
Object object = new Object();
public void add(int num) {
synchronized(object) {
totalNum+=num;
System.out.println("totalNum=" + totalNum);
}
}
}
URLConnection类对象可以与指定的URL建立动态连接,同时使用URLConnection类可以实现向服务器发送请求,将数据送回服务器
import java.io.*;
import java.net.*;
public class Server {
public static void main(String[] args) throws UnknownHostException,IOException {
// TODO Auto-generated method stub
ServerSocket serversocket=new ServerSocket(90);
Socket client=serversocket.accept();
InputStream in=client.getInputStream();
OutputStream out=client.getOutputStream();
DataInputStream dis=new DataInputStream(in);
DataOutputStream dos=new DataOutputStream(out);
String inputmsg=null;
System.out.println("Connetion Established!!");
while(true) {
inputmsg=dis.readUTF();
System.out.println("From Client: "+inputmsg);
dos.writeUTF("From Server: "+inputmsg.toUpperCase());
}
}
}
import java.net.*;
import java.io.*;
public class Client {
public static void main(String[] args) throws UnknownHostException,IOException {
// TODO Auto-generated method stub
Socket client=new Socket("localhost",90);
InputStream in=client.getInputStream();
OutputStream out=client.getOutputStream();
DataInputStream dis=new DataInputStream(in);
DataOutputStream dos=new DataOutputStream(out);
BufferedReader console=new BufferedReader(new InputStreamReader(System.in));
String inputmsg=null;
String outputmsg=null;
while(true) {
outputmsg=console.readLine();
if(outputmsg.contentEquals("break")) {
break;
}
dos.writeUTF(outputmsg);
inputmsg=dis.readUTF();
System.out.println(inputmsg);
}
}
}