Java笔记
Java
基础知识
public class HelloWorld
{
public static void main(String[] args)
{
System.out.println("Hello World!");
}
}
JAVA特点
对象
一个可表示的存储区域
类
- 属性:变量
- 行为:函数
class Person
{
int age;
String name;
void sayHello()
}
对象
Person p = new Person()
模块化
将属性和行为封装在类中,程序定义很多类
class Person
{
private int age;
public int getAge(){return age;}
public void setAge(int a){age=a;}
void sayHello(){…}
}
继承性
-
父类和子类之间共享数据和方法
-
父类
class person { int age; String name; void sayHello(){…} }
-
子类
class Student extends Person { String school; double score; void meetTeacher(){…} }
子类便继承了父类的那些功能属性,并且具有子类这些更新的属性
-
好处:
- 更好的进行抽象与分类
- 增加代码的重用率
- 提高维护性
多态
不同的对象收到一个调用方法可产生完全不同的效果
老师和学生虽然都被一个函数调用却能产生两种不同的打招呼方式
foo(Person p) {p.sayHello();}
foo(new Student());
foo(new Teacher());
程序的分析和设计都围绕
- 有哪些对象
- 每个类有哪些属性,方法
- 类之间的关系(继承,关联)
- 对象之间调用方法
JAVA SE类型:Application和Applet程序
- 结构和运行环境不同
- 前者是独立的程序,需要执行器(调用虚拟机)来运行
- 后者是嵌在HTML网页中的非独立的程序
由专门的appletViewer来运行或者由Web浏览器(调用JAVA虚拟机)来运行
普通的应用程序
class是主体
public类名与文件同名
main()写法固定
System.out.print 及println及printf
public class HelloWorldApp
{
public static void main(String args[])
{
System.out.println(“Hello World!”);
}
}
Applet程序
import表示导入
extends JApplet表示继承 Applet或JApplet都可以
有paint()方法,表示如何绘制
没有main()方法
import java.awt.*;
import java.applet.*;
import javax.swing.*;
public class HelloWorldApplet extends JApplet
{
public void paint(Graphics g)
{
g.drawString(“Hello World!”,20,20);
}
}
//这个.java不能单独运行
//要配合html使用
<HTML>
<HEAD><TITLE> An Applet</TITLE></HEAD>
<BODY>
<applet code= “HelloWorldApplet.class"
width=200 height=40 background=white>
</applet>
</BODY>
</HTML>
JAVA程序的基本构成
- package语句(0或1句) package edu.pku.tds.ch02;
- import语句(0或多句) import java.util.*;导入其它类的类库
- 类定义—class(1或多个) public class HelloDate {
一个文件只能有一个public类(与文件同名)
类=类头+类体
类成员=字段(field)+方法(method)
字段(field,属性,变量)
方法(method,函数)
方法=方法头+方法体
JDK安装后的文件夹
- bin 存放工具文件
- jre存放与java运行环境相关的文件
- demo存放一些示例文件
- include 存放与C相关的头文件
- lib存放程序库
- db数据库相关
Application编辑编译运行
程序编译
转换为字节码(bytecode)文件,扩展名.class
(.class文件中包含java虚拟机的指令)
编译使用JDK工具javac.exejavac Hello.java
程序运行
执行.class文件中的指令的过程java Hello
不能写成java Hello.class
Applet编辑编译运行
在HTML中嵌入Applet
使用标签<applet code= “HelloWorldApplet.class" width=200 height=40 background=white> appletViewer HelloWorldApplet.html
工具
主要工具
javac 编译
java 运行(控制台及图形界面程序)
javaw运行图形界面程序
appletViewer运行apple程序
常用的工具
jar 打包工具
javadoc生成文档
javap 查看类信息及反汇编
使用jar打包
编译javac A.java
打包jar cvfm A.jar A.man A.class
c表示create,v表示显示详情verbose,f表示指定文件名,m表示清单文件
运行java-jar A.jar
其中A.man是清单文件(manifest),内容如下:
manifest-Version:1.0
Class-Path:.
Main-Class:A
清单文件可以任意命名,常见的使用MANIFEST.MF
使用JavaDoc生成文档
Javadoc -d目录名xxx.java
/** */这其中可以用一下标记
@auther对类说明 标记开发该类模块的作者
@version对类的说明 标明该类模块的版本
@see 对类,属性,方法的说明 参考转向,也就是相关主题
@param 对方法的说明 对方法中某参数的说明
@return 对方法的说明 对方法返回值的说明
@exception 对方法的说明 对方法可能抛出的异常进行说明
使用javap
- 使用javap查看类的信息:
javap 类名 - 使用javap反汇编:
javap -c 类名
输入输出
文本界面
使用java.util.Scanner类
import java.util.Scanner;
class ScannerTest
{
public static void main(String[] args)
{
Scanner scanner = new Scanner(System.in);
System.out.print(“请输入一个数”);
int a = scanner.nextInt();
System.out.printf(“%d的平方是%d\n”,a,a*a);
}
}
使用java.io包
System.in.read()
System.out.print()及println,printf 类似于C语言
AppCharInOunt.java得到一个字符
char c = ‘ ’;
System.out.print(“PPlease input a char:”)
try
{
c = (char) System.in.read();
}
catch(IOException e){}
System.out.println(“You have entered:” + c);
AppLineInOut.java输入输出行
try
{
BufferedReader in = new BufferedReader(
new InputStreamReader(System.in();
s = in.readLine();
}
catch(IOExeption e){}
AppNumInout.java输入输出数字
BufferedReader in = new BufferedReader(
new InputStreamReader(System.in));
System.out.print(“Please input an int:”);
s = in.readLine();
n = Integer.parseInt(s);
//如果是double类型则为Double.parseDouble(s)
图形界面下
使用文本框对象TextField获取输入数据
使用标签对象Label或文本框对象输出数据
使用命令按钮Button来执行命令
Java Application要创建自己的图形界面
通过Frame创建自己的用户界面,在构建AppFrame时,设定该Frame大小,并用setVisible(true)方法显示出来
- add(xxxx)加入对象
- btn.addActionListener处理事件
- actionPerformed()函数 具体处理事件
setLayout(new FlowLayout());
add(in);
add(btn);
add(out);
btn.addActionListener(new BtnActionAdapter());
class BtnActionAdapter implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String s = in.getText();
double d = Double.parseDouble(s);
double sq = Math.sqrt(d);
out.setText( d + “的平方根是:” + sq);
}
}
//Java8后可简化为:
btn.addAcitonListener(e->{
String s = in.getText();
double d = Double.parseDouble(s);
double sq = Math.sqrt(d);
out.setText( d + “的平方根是:” + sq);
});
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class AppGraphInOut {
public static void main(String args[]) {
new AppFrame();//在main里面构建一个Frame对象
}
}
class AppFrame extends JFrame {
JTextField in = new JTextField(10);
JButton btn = new JButton("求平方");
JLabel out = new JLabel("用于显示结果的标签");
public AppFrame() {
setLayout(new FlowLayout());
getContentPane().add(in);//流式内容
getContentPane().add(btn);
getContentPane().add(out);
btn.addActionListener(new BtnActionAdapter());
setSize(400, 100);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setVisible(true);
}
class BtnActionAdapter implements ActionListener {
public void actionPerformed(ActionEvent e) {
String s = in.getText();
double d = Double.parseDouble(s);
double sq = d * d;
out.setText(d + "的平方是:" + sq);
}
}
}
Applet输入输出
AppletInOut.java
在init()中:
add(xxx)加入对象
btn.addActionListener 处理事件
actionPerformed()函数 具体处理事件
import javax.swing.*;
import java.awt.*;
public class AppletInOut8 extends JApplet {
JTextField in = new JTextField(10);
JButton btn = new JButton("求平方根");
JLabel out = new JLabel("用于显示结果的标签");
public void init() {
setLayout(new FlowLayout());
add(in);
add(btn);
add(out);
btn.addActionListener(e -> {
String s = in.getText();
double d = Double.parseDouble(s);
double sq = Math.sqrt(d);
out.setText(d + "的平方根是:" + sq);
});
}
}
同时作为Application和Applet的程序三个条件
- 是Applet的派生
- 含有main();
- 在main()中创建一个用户界面,并将这个Applet加入
import javax.swing.*;
import java.awt.*;
public class AppAppletInOut extends JApplet {
public static void main(String args[]) {
JFrame frame = new JFrame();
AppAppletInOut app = new AppAppletInOut();
app.init();
frame.getContentPane().add(app);
frame.setSize(400, 100);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);//关闭窗口
frame.setVisible(true);
}
JTextField in = new JTextField(10);
JButton btn = new JButton("求平方根");
JLabel out = new JLabel("用于显示结果的标签");
public void init() {
setLayout(new FlowLayout());
add(in);
add(btn);
add(out);
btn.addActionListener(e -> {
String s = in.getText();
double d = Double.parseDouble(s);
double sq = Math.sqrt(d);
out.setText(d + "的平方根是:" + sq);
});
}
}
数据类型
基本数据类型
变量在栈,赋值时复制的是值
-
数值型
- 整数类型:byte1,short2,int4,long8
- 浮点类型:float4,double8 默认为double,或者float a=1.2f使其为float
-
字符型:char
-
布尔型:boolean
public class BooleanTest { public static void main(String args[]) { boolean a = false; boolean b = true; System.out.println(a + " " + b); } }
引用数据类型
变量引用到堆,类似指针,赋值时复制的是引用
- 类:class
- 接口:interface
- 数组
采用Unicode编码
每个字符占两个字节 char c = ‘\u0061’
进制
八进制:0开头,012
十六进制:0x或0X开头,0x12
二进制:0b或0B开头,0b00010010
无无符号数,unsigned int
类名首字母大写,其余小写
运算符
短路逻辑运算符
&& 第一个操作符为假则不判断第二个操作数
|| 第一个操作数为真则不判定第二个操作数
if((d != NULL) && (d.day > 31))
{
//则它只会先判断第一个是否成立,在第一个成立的前提下才去看第二个
}
public class LeapYear {
public static void main(String args[]) {
int year = 2003;
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
System.out.println(year + " is a leap year.");
}
else {
System.out.println(year + " is not a leap year.");
}
}
}
位运算
左移:a<<b;
最低位空出的b位补0
带符号右移:a>>b;
最高位空出的b位补原来的符号位
无符号右移:a>>>b;
最高位空出的b位补0
public class BitwiseOperators {
public static void main(String args[]) {
int a = 0b1100;
int b = 0b1010;
print("a ", a);
print("b ", b);
print("a&b", a & b);
print("a|b", a | b);
print("a^b", a ^ b);
print("~a", ~a);
print("a<<2", a << 2);
print("a>>2", a >> 2);
print("a>>>2", a >>> 2);
}
static void print(String prefix, int n) {
String s = Integer.toBinaryString(n);
while (s.length() < 4) {//长度不够就补0
s = "0" + s;
}
System.out.println(prefix + " " + s);
}
}
+可以连接字符串
public class GradeLevel {
public static void main(String args[]) {
char grade = 'C';
switch (grade) {
case 'A':
System.out.println(grade + " is 85~100");
break;
case 'B':
System.out.println(grade + " is 70~84");
break;
case 'C':
System.out.println(grade + " is 60~69");
break;
case 'D':
System.out.println(grade + " is <60");
break;
default:
System.out.println("Input Error");
}
}
}
break语句选择跳出哪一层循环
lable1:{
lable2: {
lable3: {
break label2;
}
}
}
//从里层循环直接跳出二至多层
public class Rnd_36_7
{
public static void main(String args[])
{
int a[] = new int[7];
for (int i = 0; i < a.length; i++)
{
one_num:
while (true)
{
a[i] = (int) (Math.random() * 36) + 1;
for (int j = 0; j < i; j++)
{
if (a[i] == a[j])
{
continue one_num;
}
break;
}
}
}
for (int num : a)
{
System.out.println(num + " ");
}
System.out.println();
}
}
public class Prime100Continue
{
public static void main(String args[])
{
System.out.println("****100--200的质数****");
int n = 0;
outer:
for (int i = 0; i < 200; i += 2)
{//外层循环
for (int j = 2; j < 2; j++)
{//内层循环
if (i % j == 0)
{//不是质数,则继续外层循环
continue outer;
}
}
System.out.println(" " + i);//显示质数
n++;//计算个数
if (n < 10)
{//未满十个数不换行
continue;
}
System.out.println();
n = 0;
}
System.out.println();
}
}
import javax.swing.*;
import java.awt.*;
public class AutoScore extends JFrame
{
public static void main(String [] argv)
{
JFrame frame = new AutoScore();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600,600);
frame.setVisible(true);
}
public AutoScore()
{
init();
setSize(400, 350);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public void init()
{
setLayout(null);//手动布局
setSize(400, 350);
btnNew.setLabel("出题");
getContentPane().add(btnNew);
btnNew.setBackground(java.awt.Color.lightGray);
btnNew.setBounds(36, 96, 98, 26);
btnJudge.setLabel("判分");
getContentPane().add(btnJudge);
btnJudge.setBackground(java.awt.Color.lightGray);
btnJudge.setBounds(216, 96, 94, 25);
lblA.setText("text");
getContentPane().add(lblA);
lblA.setFont(new Font("Dialog", Font.PLAIN, 24));
lblA.setBounds(36, 24, 36, 36);
lblOp.setText("text");
getContentPane().add(lblOp);
lblOp.setFont(new Font("Dialog", Font.PLAIN, 24));
lblOp.setBounds(72, 24, 36, 36);
lblB.setText("text");
getContentPane().add(lblB);
lblB.setFont(new Font("Dialog", Font.PLAIN, 24));
lblB.setBounds(108, 24, 33, 36);
label5.setText("=");
getContentPane().add(label5);
label5.setFont(new Font("Dialog", Font.PLAIN, 24));
label5.setBounds(168, 24, 33, 36);
getContentPane().add(txtAnswer);
txtAnswer.setFont(new Font("Dialog", Font.PLAIN, 24));
txtAnswer.setBounds(216, 24, 85, 42);
listDisp.setFont(new Font("Dialog", Font.PLAIN, 24));
getContentPane().add(listDisp);
listDisp.setBounds(36, 144, 272, 106);
SymAciton lSymAction = new SymAciton();
btnNew.addActionListener(lSymAction);
btnJudge.addActionListener(lSymAction);
}
java.awt.Button btnNew = new java.awt.Button();
java.awt.Button btnJudge = new java.awt.Button();
java.awt.Label lblA = new java.awt.Label();
java.awt.Label lblOp = new java.awt.Label();
java.awt.Label lblB = new java.awt.Label();
java.awt.Label label5 = new java.awt.Label();
java.awt.TextField txtAnswer = new java.awt.TextField();
java.awt.List listDisp = new java.awt.List(0);
class SymAciton implements java.awt.event.ActionListener
{//接口
public void actionPerformed(java.awt.event.ActionEvent event)
{//方法
Object object = event.getSource();
if (object == btnNew)
{
btnNewActionPerformed(event);
}
else
{
btnJudgeActionPerformed(event);
}
}
}
void btnNewActionPerformed(java.awt.event.ActionEvent event)
{
a = (int) (Math.random() * 9 + 1);
b = (int) (Math.random() * 9 + 1);
int c = (int) (Math.random() * 4);
switch (c)
{
case 0:
op = "+";
result = a + b;
break;
case 1:
op = "-";
result = a - b;
break;
case 2:
op = "*";
result = a * b;
break;
case 3:
op = "/";
result = a / b;
break;
}
lblA.setText("" + a);
lblB.setText("" + b);
lblOp.setText("" + op);
txtAnswer.setText("");
}
int a = 0, b = 0;
String op = "";
double result = 0;
void btnJudgeActionPerformed(java.awt.event.ActionEvent event)
{
String str = txtAnswer.getText();
double d = Double.valueOf(str).doubleValue();
String disp = "" + a + op + b + "=" + str + "";
if (d == result)
{
disp += "Yes";
}
else
{
disp += "No";
}
listDisp.add(disp);
}
}
import javax.swing.*;
import java.awt.*;
public class Circle99Frame extends JFrame
{
public static void main(String[] argv)
{
JFrame frame = new Circle99Frame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 600);
frame.setVisible(true);
}
public void paint(Graphics g)
{
g.drawString("circle 90", 20, 20);
int x0 = getSize().width / 2;
int y0 = getSize().height / 2;
for (int r = 0; r < getSize().height / 2; r += 10)
{
g.setColor(getRandomColor());
g.drawOval(x0 - r, y0 - r, r * 2, r * 2);
}
}
Color getRandomColor()
{
return new Color(
(int) (Math.random() * 255),
(int) (Math.random() * 255),
(int) (Math.random() * 255)
);
}
}
数组
数组定义与为数组元素分配空间分开进行
int a[] = new int[3];//分配空间
a[0] = 3;
a[1] = 9;
a[2] = 8;
MyDate []dates = new MyDate[3];
dates[0] = new MyDate(22,7,1964);
dates[1] = new MyDate(1,1,2000);
dates[2] = new MyDate(22,12,1964);
静态初始化值
int[] a = {3,9,8}; 或 int[] a = new int[] {3,9,8}
MyDate[] dates = {
new MyDate(22,7,1964),new MyDate(1,1,2000),new MyDate(22,12,1964)
};
a.length得知数组长度
增强for语句
可以方便的处理数组,集合中各元素
int[] ages = new int[10];
for ( int age : ages )
{//这种语句是只读式遍历
System.out.println(age);
}
数组复制
数组复制System.arraycopy提供了数组元素复制功能:System.arraycopy(source,1,dest,0,source.Length);
将source数组中第1个元素开始
复制到dest数组中第0个开始,一共复制source.Length这么长
二维数组
二维数组是数组的数组
int [][] a = { {1,2},{3,4,0,9},{5,6,7} };
int [][] t = new int [3][];
t[0] = new int [2];//开的数组不一定是完整的矩形
t[1] = new int [4];
t[2] = new int [3];
类
class Person
{
String name;
int age;
void sayHello()
{
System.out.println(“Hello! My name is” + name);
}
}
- 类=类头+类体
- 类成员=字段(field)+方法(method)
- 字段(field,属性,变量)
- 方法(method,函数)
- 方法=方法头+方法体
构造方法
Person( String n,int a)
{
name = n;
age = a;
}
多态
方法有相同的名字,编译时能识别出来
签名不同:参数个数不同或参数类型不同
通过方法重载可以实现多态
在方法及构造方法中可以使用this.+字段来调用本局部变量的值
类的继承
- 一个类只能有一个继承的父类
- 子类继承父类的状态和行为
- 可以修改父类的状态或重载父类的行为
- 可以添加新的状态和行为
- Java的继承通过extends关键字来实现:
class Student extends Person
如果没有extends子句,则该类默认为java.lang.Object的子类
所有的类都是间接或直接地继承java.lang.Object得到的
字段(属性,变量)
-
字段的继承
- 字类可以继承父类的所有字段
- Student自动具有Person的属性(name,age)
-
字段的隐藏
子类重新定义一个与从父类那里继承来的域变量完全相同的变量,称为域的隐藏
-
字段的添加
在定义子类时,加上新的域变量,据可以使子类比父类多一些属性
class Student extends Person { String school; int score; }
方法
-
方法的继承
父类的非私有方法也可以被子类自动继承
Student自动继承Person的方法sayHello和isOlderThan -
方法的覆盖(Override)(修改)
子类也可以重新定义与父类同名的方法,实现对父类方法的覆盖
@Override的使用@Override void sayHello() { System.out.println("Hello! My name is" + name + ".My school is " + school); }
通过方法的覆盖,能够修改对象同名方法的具体实现方法
-
方法的添加
子类可以新加一些方法,以针对子类实现相应的功能
在类Student中,加入一个方法,对分数判断:boolean isGoodStudent() { return score >= 90; }
-
方法的重载
一个类中可以有几个同名的方法,这称为方法的重载(Overload)
同时还可以重载父类的同名方法.与覆盖方法不同的是,重载不要求参数类型列表相同
重载的方法实际是新加的方法在类Student中,重载一个名为sayHello的方法:
void sayHelo(Student another) { System.out.println("Hi!"); if( school.quals( another.school )) { System.out.println(" Schoolmates "); } }
super的使用
-
使用super访问父类的域和方法
由于继承,使用this可以访问父类的域和方法
但有时为了明确地指明父类的域和方法,就要用关键字super父类Student有一个域age,在子类Student中用age,this.age,super.age来访问age是完全一样的
void testThisSuper() { int a; a = age; a = this.age; a = super.age; }
有时需要使用super以区别同名的域与方法
-
使用super可以访问被子类所隐藏了的同名变量
-
当覆盖父类的同名方法的同时,又要调用父类的方法,就必须使用super
void sayHello() { super.sayHello(); System.out.println("My school is" + school); }
-
-
使用父类的构造方法
构造方法是不能继承的
比如,父类Person有一个构造方法Person(String,int)不能说子类Student也自动有一个构造方法Student(String,int)但是,子类在构造方法中,可以用super来调用父类的构造方法
Student(String name,int age,String school) { super(name,age); this.school=school; }
使用时super只能放在第一句
public static void main( String [] args )
{
Person p = new Person("Liming",50);//正常情况
Student s = new Student("Wangqiang",20,"PKU");//正常情况
Person p2 = new Student("Zhangyi",18,"THU");
Student s2 = (Student) p2;
Student s3 = (Student) p;
p.sayHello(s);
Person [] manypeople = new Person[100];
manypeople[0] = new Person("Li",18);
manypeople[1] = new Student("Wang",18,"PKU");
}
包
package pkg1[.pkg2[.pkg3…]];
import package
修饰符
访问修饰符
public private
同一个类中 | 同一个包中 | 不同包中的子类 | 不同包中的非子类 | |
---|---|---|---|---|
private | yes | |||
默认 | yes | yes | ||
protected | yes | yes | yes | |
public | yes | yes | yes | yes |
其它修饰符
abstract
基本含义 | 修饰类 | 修饰成员 | 修饰局部变量 | |
---|---|---|---|---|
static | 静态的,非实例的,类的 | 可以修饰内部类 | yes | |
final | 最终的,不可改变的 | yes | yes | yes |
abstract | 抽象的,不可实例化的 | yes | yes |
-
static字段
- 静态字段最本质的特点是
他们是类的字段,不属于任何一个对象的实例 - 他不保存在某个对象实例的内存区间,二十保存在类的内存区域的公共存储单元
- 类变量名可以通过类名直接访问,也可以通过实例对象来访问,两种方法的结果是相同的
- 如System类的in和out对象,就是属于类的域,直接用类名来访问,如System.in和System.out
class Person //此时的totalNum代表人类的总人数,他与具体对象实例无关 //从某种意义上讲,他可以用来表示全局变量,属于整个类的 { static long totalNum; int age; String Name; }
- 静态字段最本质的特点是
-
final
- final类
这个类不能被继承,即不可能有子类 - final方法
final修饰符所修饰的方法,是不能被子类所覆盖的方法 - final字段和局部变量
他们的值一旦给定,就不能更改,是一个只读量,能且只能被赋值一次 - 同时被static final两个修饰符所限定时候,它可以表示常量
- 关于赋值
- 定义static final域默认初始化为
- 数值为0
- boolean为false
- 引用型为null
- 定义final字段时,若不是static的域,则必须且只能赋值一次
- 定义final局部变量时,也必须且只能复制一次
- 定义static final域默认初始化为
- final类
-
abstract类
- abstract类
凡是用abstract修饰符修饰的类被称为抽象类
抽象类不能被实例化 - abstract方法
被abstract所修饰的方法叫抽象方法,抽象方法的作用在为所有子类定义一个统一的接口.
对抽象方法只需声明,而不需实现,即用分号;而不是{}
一旦某个类中包含了absract方法,则这个类必须声明为abstract类
- abstract类
接口
接口,某种特定的约定
- 定义接口 interface
所有方法都自动是public abstract - 实现接口 implements
可以实现多继承
与类的继承关系无关
面向接口编程
interface Collection
{
void add(Object obj);
void delete(Object obj);
Object find(Object obj);
int size();
}
枚举
enum Light{Red, Yellow, Green}
Light light = Light.Red;
swtch(light)
{
case Red:
break;
}
Java中的枚举是用class来实现的,可以复杂的使用
完整定义
完整的类定义
[public][abstract|final] class className[extends superclassName]
[implemrnts InterfaceNameList]
{//类声明
[public|protected|private][static][final][transient][volatile] type variableName;//成员变量生命,可为多个
[public|protected|private][static][final|abstract][native][synchronized]
return Type methodName([paramList])//方法定义及实现,可为多个
[throws exceptionList]
{
statements
}
}
完整的接口定义
[public] interface InterfaceName [extends superInterfaceList]
{//接口声明
type constantName = value;//常量声明,可为多个
return TypeMethodName([paraList]);//方法声明,可为多个
}
固定的声明方式
构造方法
className([paramlist])
{
}
main() 方法
public static void main(String args[])
{
}
finalize()方法
protected void finalize()throws throwable
{
}
完整的java源文件
package packageName;//指定文件中的类所在的包,0个或1个
import packageName.[className|*];//指定引入的类,0个或多个
public classDefinition//属性为public的类定义,0个或1个
interfaceDefinition and class Definition//接口或类定义,0个或多个
源文件的名字必须与属性为public的类的类名完全相同
在一个.java文件中,package语句和public类最多只能有1个
变量及其传递
基本类型变量与引用型变量
基本类型:其值直接cunyu 变量中
引用型的变量除占据一定的内存空间外,它所引用的对象实体(由new创建)也要占据一定空间
public class MyDate {
private int day;
private int month;
private int year;
public MyDate(int y, int m, int d) {
year = y;
month = m;
day = d;
}
void addYear() {
year++;
}
public void display() {
System.out.println(year + '-' + month + '-' + day);
}
public static void main(String args[]) {
MyDate m = new MyDate(2003, 9, 22);
MyDate n = m;
n.addYear();
m.display();
n.display();
}
}
//由于是new出来的变量,所以是一个引用的对象,故改变其中的一个会影响到所有的
字段变量与局部变量
-
前者是在类中,后者是方法中定义的变量或方法的参变量
-
从内存角度看
-
存储位置,字段变量为对象的一部分,存在于堆中,局部变量存在于栈中。
-
生命周期不同
-
初始值:字段变量可以自动赋初值,局部变量则须显式赋值
class Test() { int a; void m(){ int b; System.out.println(b);//编译不能通过,需要初始化 } }
-
-
从语法角度来看
- 字段变量属于类,可以被public,private,static,final修饰
- 局部变量不能够被访问控制符及static修饰
- 都可以被final修饰
变量的传递
调用方法时,要传递参数.在传递参数时,Java是值传递,即,是将表达式的值复制给形式参数.
对于引用型变量,传递的值是引用值,而不是复制对象实体(可以改变对象的属性)
public class TransByValue {
public static void main(String[] args) {
int a = 0;
modify(a);
System.out.println(a);//0
int[] b = new int[1];
modify(b);
System.out.println(b[0]);//1
}
public static void modify(int a) {
a++;//仅仅是传了个参数进来,对外面的a不影响
}
public static void modify(int[] b) {
b[0]++;
b = new int[5];
}
}
变量的返回
方法的返回:
- 返回基本类型
- 返回引用类型。它就可以存取对象实体
Object getNewObject()
{
Object obj = new Object();
return obj;
}
调用时:object p = GetNewObject();
多态
- 指一个程序中相同的名字表示不同的含义的情况
- 两种情况
- 编译时多态:
重载(多个同名的不同方法) - 运行时多态:
- 覆盖(子类对父类方法进行覆盖)
- 动态绑定–虚方法调用
- 在调用方法时,程序会正确地调用子类对象的方法
- 编译时多态:
- 多态的特点大大提高了程序的抽象程度和简洁性
上溯造型
是把派生类型当作基本类型处理
Person p = new Student();
void fun(Person p){...}
fun(new Person());
虚方法调用
用虚方法调用,可以实现运行时的多态
- 子类重载了父类方法时,运行时系统根据调用该方法的实例的类型来决定哪个方法调用
- 所有的非final类方法都会自动地进行动态绑定
import java.awt.*;
public class TestVirtualInvoke {
static void doStuff(Shape s) {
s.draw();
}
public static void main(String[] args) {
Circle c = new Circle();
Triangle t = new Triangle();
Line l = new Line();
doStuff(c);
doStuff(t);
doStuff(l);
}
}
class Shape {
void draw() {
System.out.println("Shape Drawing");
}
}
class Circle extends Shape {
void draw() {
System.out.println("Draw Circle");
}
}
class Triangle extends Shape {
void draw() {
System.out.println("Draw Three Lines");
}
}
class Line extends Shape {
void draw() {
System.out.println("Draw Line");
}
}
动态类型确定
变量instanceof类型
结果是boolean值
class InstanceOf {
public static void main(String[] args) {
Object[] things = new Object[3];
things[0] = new Integer(4);
things[1] = new Double(3.14);
things[2] = new String("2.09");
double s = 0;
for (int i = 0; i < things.length; i++) {
if (things[i] instanceof Integer)//判断其是不是个整数
s += ((Integer) things[i]).intValue();
else if (things[i] instanceof Double)//判断其是不是个双精度
s += ((Double) things[i]).doubleValue();
}
System.out.println("sum=" + s);
}
}
什么时候不是虚方法
Java中,普通方法是虚方法
但static,private方法不是虚方法调用
static,private与虚方法编译后用的指令是不同的
class JavaP3methods {
void f() {
}
private void p() {
}
static void s() {
}
public static void main(String... argv) {
JavaP3methods obj = new JavaP3methods();
obj.f();
obj.p();
obj.s();
}
}
三种非虚的方法
- static方法,以声明的类型为准,与实例类型无关
- private方法子类看不见,也不会被虚化
- final方法子类不能覆盖,不存在虚化问题
class TestStaticInvoke {
static void doStuff(Shape s) {
s.draw();
}
public static void main(String[] args) {
Circle c = new Circle();
Triangle t = new Triangle();
Line l = new Line();
doStuff(c);//由于是定义的是static类所以只跟你定义的类型有关系
doStuff(t);//此处都是跟shape有关
doStuff(l);
Shape s = new Circle();
doStuff(s);//声明了shape类故只能输出ShapeDrawing
s.draw();
Circle c2 = new Circle();
c2.draw();//声明了circle类之后调用了其本身的方法故输出DrawCircle
}
}
class Shape {
static void draw() {
System.out.println("Shape Drawing");
}
}
class Circle extends Shape {
static void draw() {
System.out.println("Draw Circle");
}
}
class Triangle extends Shape {
static void draw() {
System.out.println("Draw Three Lines");
}
}
class Line extends Shape {
static void draw() {
System.out.println("Draw Line");
}
}
/*
Shape Drawing
Shape Drawing
Shape Drawing
Shape Drawing
Shape Drawing
Draw Circle
*/
构造方法
对象都有构造方法,如果没有,编译器加一个default构造方法
-
调用本类或父类的构造方法
- this调用本类的其他构造方法
- super调用直接父类的构造方法
- this或super要放在第一条语句,且只能够有一条
-
如果没有this及super,则编译器自动加上super(),即调用直接父类不带参数的构造方法
-
因为必须令所有父类的构造方法都得到调用,否则整个对象的构造就可能不正确
class ConstructCallThisAndSuper { public static void main(String[] args) { Person p = new Graduate();//创建一个人p,他是一个研究生 } } class Person { String name; int age; Person() { } Person(String name, int age) { this.name = name; this.age = age; System.out.println("In Person(String,int)"); } } class Student extends Person { String school; Student() { this(null, 0, null); System.out.println("In Student()"); } Student(String name, int age, String school) { super(name, age); this.school = school; System.out.println("In Student(String,int,String)"); } } class Graduate extends Student { String teacher = ""; Graduate() { //super();加上与不加上都可,编译器会自动的加上super,因为他会继承父类 System.out.println("In Graduate()"); } } /* 会调用一系列的构造方法 In Person(String,int) In Student(String,int,String) In Student() In Graduate() */
一个问题
class A{ A(int a){ } } class B extends A{ B(String s){ //编译不能通过 } } 编译器会自动调用 B(String s){ super(); }出错
解决方法:
- 在B的构造方法中加入super(3);
- 在A中加入一个不带参数的构造方法,
A(){}
- 去掉A中全部的构造方法,则编译器会自动加入一个不带参数的构造方法,称为默认的构造方法。
创建对象的初始化
p = new Person(){{ age = 18; name = "李明";}};
注意双括号
实例初始化与静态初始化
实例初始化
{语句}
在类中直接写,实例初始化,先于构造方法中的语句执行
静态初始化
static {语句}
静态初始化,在第一次使用这个类时执行,但其执行的具体时机是不确定的,但可以肯定的是:总是先于实例的初始化
class InitialTest {
public static void main(String[] args) {
new InitialTest2(6);
}
int n = 10; //step2
{
n++;
System.out.println("InitialTest..." + n);
}
static int x;
static {
x++;
System.out.println("static..." + x);
}
}
class InitialTest2 extends InitialTest {
InitialTest2(int a) {//构造函数
this.a = a;
System.out.println("this.a=" + a);
}
int a;
{
System.out.println("InitialTest2..." + this.a);
}
static {
x++;
System.out.println("static2..." + x);
}
}
/*
先构造一个子类,但是static初始化先运行
然后运行实例初始化,最后在构造函数
static...1
static2...2
InitialTest...11
InitialTest2...0
this.a=6
*/
构造方法的执行过程
- 调用本类或父类的构造方法,直至最高一层(Object)
- 按照声明顺序执行字段的初始化赋值
- 执行构造函数中的各语句
简单的说:先父类构造,再本类成员赋值,最后执行构造方法中的语句
class ConstructSequence {
public static void main(String[] args) {
Person p = new Student("李明", 18, "北大");
}
}
class Person {
String name = "未命名"; //step 2
int age = -1;
Person(String name, int age) {
super(); //step 1
//step 3
System.out.println("开始构造Person(),此时this.name=" + this.name + ",this.age=" + this.age);
this.name = name;
this.age = age;
System.out.println("Person()构造完成,此时this.name=" + this.name + ",this.age=" + this.age);
}
}
class Student extends Person {
String school = "未定学校"; //step2
Student(String name, int age, String school) {
super(name, age); //step 1
//step 3
System.out.println("开始构造Student(),此时this.name=" + this.name + ",this.age=" + this.age + ",this.school=" + this.school);
this.school = school;
System.out.println("Student()构造完成,此时this.name=" + this.name + ",this.age=" + this.age + ",this.school=" + this.school);
}
}
/*
开始构造Person(),此时this.name=未命名,this.age=-1
Person()构造完成,此时this.name=李明,this.age=18
开始构造Student(),此时this.name=李明,this.age=18,this.school=未定学校
Student()构造完成,此时this.name=李明,this.age=18,this.school=北大
*/
一个问题
构造方法内部调用别的方法,这个方法恰好是个虚方法,结果如何?
class ConstructInvokeMetamorph {
public static void main(String[] args) {
Person p = new Student("李明", 18, "北大");
}
}
class Person {
String name = "未命名";
int age = -1;
Person(String name, int age) {
this.name = name;
this.age = age;
sayHello();
//在此时调用的函数为虚函数,是子类的函数,而此时学校的信息还没有复制好,会导致出现错误
}
void sayHello() {
System.out.println("我是一个人,我名叫:" + name + ",年龄为:" + age);
}
}
class Student extends Person {
String school = "未定学校";
Student(String name, int age, String school) {
super(name, age);
this.school = school;
}
void sayHello() {
System.out.println("我是学生,我名叫:" + name + ",年龄为:" + age + ",学校在:" + school);
}
}
/*
我是学生,我名叫:李明,年龄为:18,学校在:null
*/
对象清除垃圾回收
垃圾回收,对象回收是由Java虚拟机的垃圾回收线程来完成的
为什么系统知道对象是否为垃圾:任何对象都有一个引用计数器,当其值为0时,说明该对象可以回收
System.gc()
方法,他是System类的static方法,它可以要求系统进行垃圾回收,但他仅仅只是‘建议’
-
Java中没有析构方法
-
但Object的
finalize()
有类似功能- 系统在回收时会自动调用对象的
finalize()
方法 protected void finalize() throws Throwable{}
- 系统在回收时会自动调用对象的
-
子类的
finalize()
方法- 可以在子类的
finalize()
方法释放系统资源 - 一般来说,子类的
finalize()
方法中应该调用父类的finalize()
方法,以保证父类的清理工作能够正常进行。
- 可以在子类的
-
由于
finalize()
方法的调用时机不确定,所以一般不用finalize()
-
关闭打开的文件,清除一些非内存资源等工作需要进行处理可以使用tyr-with-resource语句
-
对于实现了java.lang.AutoCloseable的对象
try( Scanner scanner = new Scanner(...) ){ ... } 会自动调用其clode()方法,相当于 finally{ Scanner.close(); }
内部类与匿名类
内部类
定义
- 将类的定义class xxxx{…}置入一个类的内部即可
- 编译器生成xxxx$xxxx这样的class文件
- 内部类不能够与外部类同名
使用
- 在封装它的类的内部使用内部类,与普通类的使用方法相同
- 在其他地方使用
- 类名前要冠以外部类的名字
- 在new创建内部类时,也要在new前面冠以对象变量
外部对象名.new 内部类名(参数)
class TestInnerClass {
public static void main(String[] args) {
Parcel p = new Parcel();
p.testShip();
Parcel.Contents c = p.new Contents(33);//要加上外部的类名
Parcel.Destination d = p.new Destination("Hawii");
p.setProperty(c, d);
p.ship();
}
}
class Parcel {
private Contents c;
private Destination d;
class Contents {//内部类
private int i;
Contents(int i) {
this.i = i;
}
int value() {
return i;
}
}
class Destination {
private String label;
Destination(String whereTo) {
label = whereTo;
}
String readLabel() {
return label;
}
}
void setProperty(Contents c, Destination d) {
this.c = c;
this.d = d;
}
void ship() {
System.out.println("move " + c.value() + " to " + d.readLabel());
}
public void testShip() {
c = new Contents(22);
d = new Destination("Beijing");
ship();
}
}
内部类使用外部类
public class TestInnerThis {
public static void main(String args[]) {
A a = new A();
A.B b = a.new B();
b.mb(333);
}
}
class A {
private int s = 111;
public class B {
private int s = 222;
public void mb(int s) {
System.out.println(s); // 局部变量s
System.out.println(this.s); // 内部类对象的属性s
System.out.println(A.this.s); // 外层类对象属性s
}
}
}
内部类的修饰符
内部类与类中的字段、方法一样是外部类的成员,它的前面也可以有访问控制符和其他修饰符
-
访问控制符:public,protected,默认及private。
外部类只能够使用public修饰或者默认 -
final,abstract
-
static修饰内部类,表明内部类实际是一种外部类
-
实例化static类时,在new前面不需要用对象实例变量
-
static类中不能访问其外部类的非static的字段及方法,既只能够访问static成员
-
static方法中不能访问非static的域及方法,也不能够不带前缀地new一个非static的内部类
-
class TestInnerStatic { public static void main(String[] args) { A.B a_b = new A().new B(); A a = new A(); A.B ab = a.new B(); Outer.Inner oi = new Outer.Inner(); //Outer.Inner oi2 = Outer.new Inner(); //!!!error //Outer.Inner oi3 = new Outer().new Inner(); //!!! error } } class A { private int x; void m() { new B(); } static void sm() { //new B(); // error!!!! } class B { B() { x = 5; } } } class Outer { static class Inner { } }
-
局部类
在一个方法中定义类,方法中的内部类
class TestInnerInMethod {
public static void main(String[] args) {
Object obj = new Outer().makeTheInner(47);
System.out.println("Hello World!" + obj.toString());
}
}
class Outer {
private int size = 5;
public Object makeTheInner(int localVar) {
final int finalLocalVar = 99;
class Inner {
public String toString() {
return (" InnerSize: " + size +
// " localVar: " + localVar + // Error!
" finalLocalVar: " + finalLocalVar
);
}
}
return new Inner();
}
}
- 同局部变量一样,方法中的内部类
- 不能够用public,private,protected,static修饰
- 但可以被final或者abstract修饰
- 可以访问其外部类的成员
- 不能够访问该方法的局部变量,除非是final局部变量
匿名类
- 一种特殊的内部类
- 没有类名,在定义类的同时就生成该对象的一个实例
- 一次性使用的类
class TestInnerAnonymous {
public static void main(String[] args) {
Object obj = new Outer().makeTheInner(47);
System.out.println("Hello World!" + obj.toString());
}
}
class Outer {
private int size = 5;
public Object makeTheInner(int localVar) {
final int finalLocalVar = 99;
return new Object() {
public String toString() {
return (" InnerSize: " + size +
" finalLocalVar: " + finalLocalVar
);
}
};
}
}
- 不取名字,直接用其父类或接口的名字
也就是说,该类是父类的一个子类,或者实现了一个接口 - 类的定义的同时就创建实例,即类的定义前面有一个new
- new 类名 或 接口名
(){...}
- 不使用关键词class,也不使用extends及implements
- new 类名 或 接口名
- 在构造对象时使用父类构造方法
- 不能够定义构造方法,因为无名字
- 如果new对象时,要带参数,则使用父类的构造方法
Lambda表达式
- (参数) -> 结果
(String s) -> s.length()
x -> x*x
() -> {System.out.println(“aaa”);}
大体相当于其他语言的 “匿名函数” 或 “函数指针”
在Java中它实际上是 “匿名类的一个实例”
Runnable dolt = new Runnable(){
public void run(){
System.out.println("aaa");
}
}
new Thread(dolt).start();
就可以写成
Runnable dolt = () -> System.out.println("aaa");
new Thread( dolt ).start();
甚至可以写为
new Thread(() -> System.out.println("aaa")).start();
例如:
写一个积分函数
double d = Integral( new Fun() {
public double fun(double x){
return Math.sin(x);
}
}, 0, Math.PI, 1e-5);
可以写为
double d = Integral( x-> Math.sin(x) , 0, Math.PI, 1e-5);
@FunctionalInterface
interface Fun {
double fun(double x);
}
public class LambdaIntegral {
public static void main(String[] args) {
double d = Integral(new Fun() {
public double fun(double x) {
return Math.sin(x);
}
}, 0, Math.PI, 1e-5);
d = Integral(x -> Math.sin(x),
0, Math.PI, 1e-5);
System.out.println(d);
d = Integral(x -> x * x, 0, 1, 1e-5);
System.out.println(d);
}
static double Integral(Fun f, double a, double b, double eps)// ���ּ���
{
int n, k;
double fa, fb, h, t1, p, s, x, t = 0;
fa = f.fun(a);
fb = f.fun(b);
n = 1;
h = b - a;
t1 = h * (fa + fb) / 2.0;
p = Double.MAX_VALUE;
while (p >= eps) {
s = 0.0;
for (k = 0; k <= n - 1; k++) {
x = a + (k + 0.5) * h;
s = s + f.fun(x);
}
t = (t1 + h * s) / 2.0;
p = Math.abs(t1 - t);
t1 = t;
n = n + n;
h = h / 2.0;
}
return t;
}
}
能写成lambda的接口要求包含最多只能有一个抽象函数
@FunctionalInterface
interface Fun{
double fun( double x );
}
装箱,枚举,注解
基本类型包装
将基本类型包装成Object引用类型
Interger包含了八类Boolean,Byte,Short,Character,Integer,Long,Float,Double
装箱Integer I = 10;
拆箱int i = I;
主要方便用于集合中Object [] are = { 1, “aaa”};
枚举
- 一种特殊的class类型
- 在简单的情况下,用法与其他语言的enum相似
enum Light {Red, Yellow, Green };
Light light = Light.Red;
- 但实际上,它生成了
class Light extends java.lang.Enum
自定义枚举
可以在enum定义体中,添加字段,方法,构造方法
enum Direction
{
EAST("东", 1),
SOUTH("南", 2),
WEST("西", 3),
NORTH("北", 4);
private Direction( String desc, int num){
this.desc = desc;
this.num = num;
}
private String desc;
private int num;
public String getDesc(){return desc;}
public int getNum(){return num;}
}
注解
在各种语法要素上加上附加信息
都是java.lang.annotation.Annotation
的子类
常用的注解
@Override 表示覆盖父类的方法
@Deprecated 表示过时的方法
@SuppressWarnings 表示让编译器不产生警告
自定义注解,比较复杂
public @interface Auther{
String name();
}
引用与指针
引用实质就是指针
但是它是受控制的,安全的
- 会检查空指针
- 没有指针运算
*(p+5)
- 不能访问没有引用到的内存
- 自动回收垃圾
-
传地址 -> 对象
- 引用类型,引用本身就相当于指针
可以用来修改对象的属性,调用对象的方法 - 基本类型:没用对应的
如交换两个整数void swap(int x, int =y) {int t = x; x = y; y =t; }
int a = 8, b = 9; swap( a, b);
一种变通的办法,传出一个有两个分量x,y的对象
- 引用类型,引用本身就相当于指针
-
指针运算 -> 数组
*(p + 5)
则可以用args[5]
-
函数指针 -> 接口,Lambda表达式
求积分,线程,回调函数,时间处理 -
指向结点的指针 -> 对象的引用
class Node{ object data; Node next; }//链表
import java.io.IOException; public class List { private Node Head = null; private Node Tail = null; private Node Pointer = null; private int Length = 0; public void deleteAll() { Head = null; Tail = null; Pointer = null; Length = 0; } public void reset() { Pointer = null; } public boolean isEmpty() { return (Length == 0); } public boolean isEnd() { if (Length == 0) throw new java.lang.NullPointerException(); else if (Length == 1) return true; else return (cursor() == Tail); } public Object nextNode() { if (Length == 1) throw new java.util.NoSuchElementException(); else if (Length == 0) throw new java.lang.NullPointerException(); else { Node temp = cursor(); Pointer = temp; if (temp != Tail) return (temp.next.data); else throw new java.util.NoSuchElementException(); } } public Object currentNode() { Node temp = cursor(); return temp.data; } public void insert(Object d) { Node e = new Node(d); if (Length == 0) { Tail = e; Head = e; } else { Node temp = cursor(); e.next = temp; if (Pointer == null) Head = e; else Pointer.next = e; } Length++; } public int size() { return (Length); } public Object remove() { Object temp; if (Length == 0) throw new java.util.NoSuchElementException(); else if (Length == 1) { temp = Head.data; deleteAll(); } else { Node cur = cursor(); temp = cur.data; if (cur == Head) Head = cur.next; else if (cur == Tail) { Pointer.next = null; Tail = Pointer; reset(); } else Pointer.next = cur.next; Length--; } return temp; } private Node cursor() { if (Head == null) throw new java.lang.NullPointerException(); else if (Pointer == null) return Head; else return Pointer.next; } public static void main(String[] args) throws IOException{ List a = new List(); for (int i = 1; i <= 10; i++) a.insert(new Integer(i)); System.out.println(a.currentNode()); while (!a.isEnd()) System.out.println(a.nextNode()); a.reset(); while (!a.isEnd()) { a.remove(); } a.remove(); a.reset(); if (a.isEmpty()) System.out.println("There is no Node in List n"); System.out.println("You can press return to quitn"); try { System. in .read(); } catch(IOException e) {} } } class Node { Object data; Node next; Node(Object d) { data = d; next = null; } }
-
使用JNI
Java Native Interface (JNI)
它允许JAVA代码和其他语言写的代码交互
相等还是不等
==
-
基本类型
-
数值类型:转换后比较
-
浮点数,最好不直接==
Double.NAN == Double.NAN结果为false -
boolean型无法与int相比较
-
Integer i = new Integer(10); Integer j = new Integer(10); System.out.println( i==j );//false,因为对象是两个 Integer m = 10; Integer n = 10; System.out.println( m==n );//true,因为对象有缓存 Integer p = 200; Integer q = 200; System.out.println( p==q );//false,因为对象是两个 -128 127
-
-
枚举类型
内部进行了唯一实例化,所以可以直接判断 -
引用对象
- 是直接看两个引用是否一样
- 如果要判断内容是否一样,则要重写equals方法
- 如果重写equals方法,则最好重写hashCode()方法
-
String对象
判断相等,一定不要用==,要用equals
但是字符串常量(String literal)及字符串常量会进行内部话(interned),相同的字符串常量是==的class TestStringEquals{ public static void main(String[] args) { String hello = "Hello", lo = "lo"; System.out.println( hello == "Hello"); //true System.out.println( Other.hello == hello ); //true System.out.println( hello == ("Hel"+"lo") ); //true System.out.println( hello == ("Hel"+lo) ); //false System.out.println( hello == new String("Hello")); //false System.out.println( hello == ("Hel"+lo).intern()); //true } } class Other { static String hello = "Hello"; }
异常处理
try{
语句组
}catch(Exception ex){
异常处理语句组;
}
import java.io.*;
public class ExceptionForNum
{
public static void main(String[] args)
{
try{
BufferedReader in = new BufferedReader(
new InputStreamReader( System.in ) );
System.out.print("Please input a number: ");
String s = in.readLine();
int n = Integer.parseInt( s );
}catch(IOException ex){
ex.printStackTrace();
}catch(NumberFormatException ex){
ex.printStackTrace();
}
}
}
JAVA中处理异常
- 抛出异常
- 运行时系统在调用栈中查找
从生成异常的方法开始进行回溯,直到找到 - 捕获异常的代码
相关语句
-
抛出异常
throw 异常对象;
-
捕获异常
try{ 语句组 }catch(异常类名 异常形式参数名){ 异常处理语句组; }catch(异常类名 异常形式参数名){ 异常处理语句组; }finally{ 异常处理语句组; } 其中,catch语句可以0至多个,可以没有finally语句
异常类型
-
Throwable
-
Error:JVM的错误
-
Exception:异常,一般所说的异常是指Exception及其子类
-
构造方法
public Exception(); public Exception(String message); Exception(String message, Throwable cause);
-
方法
getMessage() getCause() printfStackTrace()
-
-
多异常处理
子类异常排在父类前面
finally
无论是否有异常都要执行,即使其中有break等语句
class JavaPTryCatchFinally {
public static void main(String[] args) {
int a = 100;
try {
a = 200;
} catch (IndexOutOfBoundsException ex) {
a = 300;
} catch (Exception ex) {
a = 400;
} finally {
a = 500;
}
a = 600;
}
}
public class TestTryFinally {
public static String output = "";
public static void foo(int i) {
try {
if (i == 1) {
throw new Exception();
}
output += "1";
} catch(Exception e) {
output += "2";
return;
} finally {
output += "3";
}
output += "4";
}
public static void main(String args[]) {
//foo(0);
//System.out.print(output + " ");
foo(1);
System.out.println(output);
}
}
受检异常
-
Exception分两种
- RuntimeException及其子类,可以不明确处理
- 否则,成为受检的异常(checked Exception)
-
受检的异常,要求明确进行语法处理
-
要么捕(catch)
-
要么抛(throws),在方法的签名后面用throws ****来
- 在子类中,如果要覆盖父类的一个方法,若父类中的方法声明了throws异常,则子类的方法也可以throws异常
- 也可以抛出异常(更具体的异常),但不能抛出更一般的异常
import java.io.*; public class ExceptionTrowsToOther{ public static void main(String[] args){ try{ System.out.println("====Before===="); readFile(); System.out.println("====After===="); }catch(IOException e){ System.out.println(e); } } public static void readFile()throws IOException { FileInputStream in=new FileInputStream("myfile.txt"); int b; b = in.read(); while(b!= -1) { System.out.print((char)b); b = in.read(); } in.close(); } }
-
-
try(类型 变量名 = new 类型()){ ... } 将会添加了finally { 变量.close(); }
import java.io.*; class TryWithResourcesTest { public static void main(String ... args) throws IOException { String path = "c:\\aaa.txt"; System.out.println( ReadOneLine1( path ) ); System.out.println( ReadOneLine2( path ) ); } static String ReadOneLine1(String path){ BufferedReader br=null; try { br=new BufferedReader(new FileReader(path)); return br.readLine(); } catch(IOException e) { e.printStackTrace(); } finally { if(br!=null){ try{ br.close(); }catch(IOException ex){ } } } return null; } static String ReadOneLine2(String path) throws IOException { try(BufferedReader br= new BufferedReader(new FileReader(path))){ return br.readLine(); } } }
自定义异常
- 将当前捕获的异常再次抛出
throw e - 重新生成一个异常,并抛出,如:
throw new Exception(“some message”); - 重新生成并抛出一个新异常,该异常中包含了当前异常信息,
Throw new Exception(“some message”,e);
可用e.getCause()来得到内部异常
public class ExceptionCause {
public static void main(String [] args) {
try
{
BankATM.GetBalanceInfo( 12345L);
}catch(Exception e) {
System.out.println("something wrong: " + e);
System.out.println("cause:" + e.getCause());
}
}
}
class DataHouse {
public static void FindData( long ID)
throws DataHouseException
{
if( ID>0 && ID<1000)
System.out.println( "id: " + ID );
else
throw new DataHouseException("cannot find the id");
}
}
class BankATM{
public static void GetBalanceInfo( long ID)
throws MyAppException
{
try
{
DataHouse.FindData(ID);
}catch (DataHouseException e) {
throw new MyAppException("invalid id",e);
}
}
}
class DataHouseException extends Exception {
public DataHouseException( String message ) {
super(message);
}
}
class MyAppException extends Exception {
public MyAppException (String message){
super (message);
}
public MyAppException (String message, Exception cause) {
super(message,cause);
}
}
断言
assert格式:
- assert 表达式;
- assert 表达式:信息
再调试程序时
如果表达式不为true,则程序会产生异常,并输出相关的错误信息
class Assertion {
public static void main(String[] args) {
assert hypotenuse(3,4)==5 : "算法不正确";
}
static double hypotenuse( double x, double y ){
return Math.sqrt( x*x + y*y + 1);
}
}
测试函数
@Test来标注测试函数
在测试中常用的语句如下:
-
fail(信息);//表示程序出错
-
assertEqauls(参数1, 参数2);//表示程序要保证两个参数相等
-
assertNull(参数);//表示参数要为null
@Test public void testSum2(){ HelloWorld a = new HelloWorld(); assertEquals(a.sum(0,100),100); //fail("Not yet implemented"); }
语言基础
JAVA基础类库
- Java.lang JAVA核心类库
JAVA是自动导入java.lang.*的 - Java.util 实用工具
- Java.io 标准输入/输出类库
- Java.awt java.swing 图形用户界面(GUI)的类库
- Java.net 网络功能的类库
- Java.sql 数据库访问的类库
字符串
-
String类
创建之后不会再做修改和变动,即immutable -
StringBuffer,StringBuilder类
创建之后允许再做更改和变化
其中StringBuilder是JDK1.5增加的,它是非线程安全的 -
特别注意,在循环中使用String+=可能会带来效率的问题
import java.util.*; class StringAndStringBuffer { public static void main(String[] args) { String a = "a"; String s = ""; StringBuffer sb = new StringBuffer(); final int N = 10000; long t0 = System.currentTimeMillis(); for( int i=0; i<N; i++) s+=a; long t1 = System.currentTimeMillis(); for( int i=0; i<N; i++) sb.append(a); long t2 = System.currentTimeMillis(); System.out.println(t1-t0); System.out.println(t2-t1); } }
-
String类对象保存不可修改的Unicode字符序列
- 创建: concat,replace,replaceAll,substring,toLowerCase,toUpperCase,trim,toString
- 查找:endsWith,startsWith,indexOf,lastIndexOf
- 比较:equals,equalsIgnoreCase
- 字符串及长度:charArt,length
-
StringBuffer类对象保存可修改的Unicode字符序列
-
StringBuilder类似,效率高,不考虑线程安全性
-
构造方法
- StringBuffer()
- StringBuffer(int capacity)
- StringBuffer(String initialString)
-
修改方法:
append,insert,reverse,setCharart,setLength -
class TestStringMethod { public static void main(String[] args) { String s = new String( "Hello World" ); System.out.println( s.length() ); System.out.println( s.indexOf('o') ); System.out.println( s.indexOf("He") ); System.out.println( s.startsWith("He") ); System.out.println( s.equals("Hello world") ); System.out.println( s.equalsIgnoreCase("Hello world") ); System.out.println( s.compareTo("Hello Java") ); System.out.println( s.charAt(1) ); System.out.println( s.substring(0,2) ); System.out.println( s.substring(2) ); System.out.println( s.concat("!!!") ); System.out.println( s.trim() ); System.out.println( s.toUpperCase() ); System.out.println( s.toLowerCase() ); System.out.println( s.replace('o', 'x' ) ); System.out.println( s ); //注意,s本身没有改变 } }
-
-
字符串分割
-
java.util.StringToken类提供了对字符串进行分割的功能
-
构造
StringTokenizer(String str,String delim); -
方法:
- public int countTokens();//分割串的个数
- public boolean hasMoreTokens();//是否还有分割串
- public String nextToken();//得到下一分割串
-
import java.util.*; class TestStringTokenizer { public static void main(String[] args) { StringTokenizer st = new StringTokenizer("this is a test", " "); while (st.hasMoreTokens()) { System.out.println(st.nextToken()); } st = new StringTokenizer("253,197,546", ","); double sum = 0; while (st.hasMoreTokens()) { sum += Double.parseDouble(st.nextToken()); } System.out.println( sum ); } }
-
日期类
calendar通过getTime()得到Date,Date通过getTime()得到long
-
Calendar
- 得到一个实例 Calendar.getInstance()//Locale.ZH
- .get(DAY_OF_MONTH) .getDisplayName(DAY_OF_WEEK)
- .set .add(HOUR,1) .roll(MONTH,5)
- .setTime(date) .getTime()
-
Date
- New Date(), new Date(System.currentTimeMillis())
- .setTime(long) .getTime()
-
SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”)
.format .parse -
import java.util.Calendar; import java.util.Date; import java.text.SimpleDateFormat; import java.util.Locale; import static java.util.Calendar.*; class CalendarDate { public static void main(String[] args) throws java.text.ParseException { Calendar calendar = Calendar.getInstance(); calendar.roll( MONTH, 1); System.out.println( calendar.get(MONTH) + "月" + calendar.get( DAY_OF_MONTH ) + "日"); Date date = new Date(); SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA); System.out.println( formatter.format(date )); date = new SimpleDateFormat("yyyy-MM-dd").parse( "2013-4-23" ); calendar.setTime( date ); System.out.println( calendar.getDisplayName(DAY_OF_WEEK, LONG, Locale.CHINA) ); } }
-
JDK8以后
import java.time.*; import java.time.format.*; class CalendarDate8{ public static void main(String[] args) throws java.text.ParseException { //使用默认时区时钟瞬时时间创建 Clock.systemDefaultZone() -->即相对于 ZoneId.systemDefault()默认时区 LocalDateTime now = LocalDateTime.now(); System.out.println(now); //自定义时区 LocalDateTime now2 = LocalDateTime.now(ZoneId.of("Europe/Paris")); System.out.println(now2);//会以相应的时区显示日期 //构造一个对象 LocalDateTime d1 = LocalDateTime.of(2013, 12, 31, 23, 59, 59); //解析String--->LocalDateTime LocalDateTime d4 = LocalDateTime.parse("2013-12-31T23:59:59"); System.out.println(d4); //使用DateTimeFormatter API 解析 和 格式化 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"); LocalDateTime d6 = LocalDateTime.parse("2013/12/31 23:59:59", formatter); System.out.println(formatter.format(d6)); //时间获取的一部分 System.out.println(d6.getYear()); System.out.println(d6.getMonth()); //这不是整数,而是枚举 System.out.println(d6.getDayOfYear()); System.out.println(d6.getDayOfMonth()); System.out.println(d6.getDayOfWeek()); System.out.println(d6.getHour()); System.out.println(d6.getMinute()); System.out.println(d6.getSecond()); System.out.println(d6.getNano()); //纳秒 //时间增减 LocalDateTime d7 = d6.minusDays(1); LocalDateTime d8 = d6.plusHours(1).plusMinutes(30); System.out.println(d7); System.out.println(d8); } }
集合
-
collection接口:有两个子接口
List:记录元素保存顺序,且允许有重复元素
Set:不记录元素的保存顺序,且不允许有重复元素 -
Map接口,映射
键-值对的集合 -
List接口
import java.util.*; public class TestArrayList{ public static void main(String[] args) { ArrayList h = new ArrayList(); h.add("1st"); h.add("2nd"); h.add(new Integer(3)); h.add(new Double(4.0)); h.add("2nd"); // 重复元素, 加入 h.add(new Integer(3)); // 重复元素,加入 m1(h); } public static void m1(List s){ System.out.println(s); } } //本应用程序输出结果如下[1st, 2nd, 3, 4.0, 2nd, 3]
-
使用增强for语句
for(Photo photo:album){ System.out.println(photo.toString()); }
-
import java.util.*; class TestList { public static void main(String[] args){ //List<Photo> album = new ArrayList<>(); List<Photo> album = new LinkedList<>(); album.add( new Photo("one",new Date(), "classroom")); album.add( new Photo("two",new Date(), "library")); album.add( new Photo("three",new Date(), "gym")); album.add( new Photo("three",new Date(), "dorm")); Iterator<Photo> iterator = album.iterator(); while(iterator.hasNext()){ Photo photo = iterator.next(); System.out.println( photo.toString() ); } for( Photo photo : album ){ System.out.println( photo ); } } } class Photo { String title; Date date; String memo; Photo(String title, Date date, String memo){ this.title = title; this.date = date; this.memo = memo; } @Override public String toString(){ return title + "(" + date + ")" + memo; } }
-
import java.util.*; public class Stacks { static String[] months = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; public static void main(String[] args) { Stack stk = new Stack(); for(int i = 0; i < months.length; i++) stk.push(months[i] + " "); System.out.println("stk = " + stk); System.out.println("popping elements:"); while(!stk.empty()) System.out.println(stk.pop()); } }
-
队列
import java.util.*; class TestQueue { public static void main(String[] args) { Queue q = new Queue(); for( int i=0; i<5; i++ ) q.enqueue( ""+i ); while( ! q.isEmpty() ) System.out.println( q.dequeue() ); } } class Queue extends LinkedList { void enqueue( Object obj ){ addLast( obj ); } Object dequeue(){ return removeFirst(); } public boolean isEmpty(){ return super.isEmpty(); } }
Set集
两个重要的实现 HashSet及TreeSet
Set中对象不重复:HashCode()不等
Map集
map是键值对的集合
import java.util.*;
class TestMap
{
public static void main( String[] args){
//Map<String, String> map = new HashMap<String, String>();
Map<String, String> map = new TreeMap<String, String>();
map.put("b", "Brazil");
map.put("r", "Russia");
map.put("i", "India");
map.put("c", "China");
map.put("k", "South Africa");
//map.put(new String("c"), "China2");
//map.put(new String("b"), "Brazil3");
System.out.println( map.get("c") );
for( String key : map.keySet() )
System.out.println( key +":" + map.get(key) );
for( String value : map.values() )
System.out.println( value );
for( Map.Entry<String,String> entry : map.entrySet() )
System.out.println( entry.getKey() +":" + entry.getValue() );
Iterator it = map.entrySet().iterator();
while(it.hasNext()){
Map.Entry<String,String> entry = (Map.Entry<String,String>)it.next();
System.out.println( entry.getKey() +":" + entry.getValue() );
}
}
}
排序查找
排序
Arrays类
Arrays.asList(10,7,6,5,9)//可以直接得到一个List对象
Arrays类提供sort()和binarySearch()
// Testing the sorting & searching in Arrays
import java.util.*;
public class TestArraysSort {
static Random r = new Random();
static String ssource =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
"abcdefghijklmnopqrstuvwxyz";
static char[] src = ssource.toCharArray();
// Create a random String
public static String randString(int length) {
char[] buf = new char[length];
int rnd;
for(int i = 0; i < length; i++) {
rnd = Math.abs(r.nextInt()) % src.length;
buf[i] = src[rnd];
}
return new String(buf);
}
// Create a random array of Strings:
public static
String[] randStrings(int length, int size) {
String[] s = new String[size];
for(int i = 0; i < size; i++)
s[i] = randString(length);
return s;
}
public static void print(byte[] b) {
for(int i = 0; i < b.length; i++)
System.out.print(b[i] + " ");
System.out.println();
}
public static void print(String[] s) {
for(int i = 0; i < s.length; i++)
System.out.print(s[i] + " ");
System.out.println();
}
public static void main(String[] args) {
byte[] b = new byte[15];
r.nextBytes(b); // Fill with random bytes
print(b);
Arrays.sort(b);
print(b);
int loc = Arrays.binarySearch(b, b[10]);
System.out.println("Location of " + b[10] +
" = " + loc);
// Test String sort & search:
String[] s = randStrings(4, 10);
print(s);
Arrays.sort(s);
print(s);
loc = Arrays.binarySearch(s, s[4]);
System.out.println("Location of " + s[4] +
" = " + loc);
}
}
关于比较
-
对象是java.lang.Comparable
实现方法public int compareTo(Object obj){ return this.price - ((Book)obj).price; }
-
提供一个java.lang.Comparator
实现方法public int compare(T 01,T o2)
自定义排序
import java.util.*;
class TestCollectionsSort
{
public static void main(String[] args)
{
List<Person> school = new ArrayList<Person>();
school.add( new Person("Li",23));
school.add( new Person("Wang",28));
school.add( new Person("Zhang",21));
school.add( new Person("Tang",19));
school.add( new Person("Chen",22));
school.add( new Person("Zhao",22));
System.out.println( school );
Collections.sort( school, new PersonComparator() );
System.out.println( school );
int index = Collections.binarySearch(
school, new Person("Li",23), new PersonComparator() );//给他一个比较器
if( index >=0 )
System.out.println( "Found:" + school.get( index ));
else
System.out.println( "Not Found!" );
}
}
class Person
{
String name;
int age;
public Person( String name, int age){
this.name=name;
this.age=age;
}
public String toString(){
return name+":"+age;
}
}
class PersonComparator implements Comparator
{//实现一个自定义排序
public int compare( Object obj1, Object obj2 ){
Person p1 = (Person)obj1;
Person p2 = (Person)obj2;
if( p1.age > p2.age ) return 1;
else if(p1.age<p2.age) return -1;
return p1.name.compareTo( p2.name );
}
}
import java.util.*;
class TestCollectionsSortByLambda
{
public static void main(String[] args)
{
List<Person> school = new ArrayList<>();
school.add( new Person("Li",23));
school.add( new Person("Wang",28));
school.add( new Person("Zhang",21));
school.add( new Person("Tang",19));
school.add( new Person("Chen",22));
school.add( new Person("Zhao",22));
System.out.println( school );
Collections.sort( school, (p1,p2)->p1.age-p2.age );
System.out.println( school );
int index = Collections.binarySearch(
school, new Person("Li",23), (p1,p2)->p1.age-p2.age );
if( index >=0 )
System.out.println( "Found:" + school.get( index ));
else
System.out.println( "Not Found!" );
}
}
class Person
{
String name;
int age;
public Person( String name, int age){
this.name=name;
this.age=age;
}
public String toString(){
return name+":"+age;
}
}
泛型
使用泛型可以针对不同的类有相同的处理方法
Vector <String> v = new Vector <String> ();
v.addElement("one");
String s = v.elementAt(0);
import java.util.*;
class GenericTreeClass {
public static void main(String[] args){
TNode<String> t = new TNode<>("Roo");
t.add("Left"); t.add("Middle"); t.add("Right");
t.getChild(0).add("aaa");
t.getChild(0).add("bbb");
t.traverse();
}
}
class TNode<T>
{
private T value;
private ArrayList<TNode<T>> children = new ArrayList<>();
TNode(T v) { this.value = v; }
public T getValue() { return this.value; }
public void add(T v) {
TNode<T> child = new TNode<>(v);
this.children.add(child);
}
public TNode<T> getChild(int i) {
if ((i < 0) || (i > this.children.size())) return null;
return (TNode<T>)this.children.get(i);
}
public void traverse() {
System.out.println(this.value);
for (TNode child : this.children)
child.traverse();
}
import java.util.*;
class GenericMethod {
public static void main(String[] args){
Date date = BeanUtil.<Date>getInstance("java.util.Date");
System.out.println(date);
}
}
class BeanUtil{
public static <T> T getInstance( String clzName ){
try
{
Class c = Class.forName(clzName);
return (T) c.newInstance();
}
catch (ClassNotFoundException ex){}
catch (InstantiationException ex){}
catch (IllegalAccessException ex){}
return null;
}
}
对类型限定
- 使用?
Collections的reverse方法
reverse(List <?> list) - 使用extends
Set的addAll方法
addAll(Collection <? Extends E> col) - 使用super
如Collections的fill方法
fill(List <? Super T) list, T obj)
多线程
进程:一个程序的执行
线程:程序中单个顺序的流控制
一个程序中可以含有多个线程
创建线程
-
通过继承Thread类创建线程
class MyThread extends Thread{ public void run(){ for(int i=0;i<100;i++){ System.out.print(" "+i); } } }
-
通过向Thread()构造方法传递Runnable对象来创建线程
class MyTask implements Runnable{ public void run(){ } } Thread thread = new Thread(mytask); thread.start();
-
使用匿名类
new Thread(){ public void run(){ for(int i=0;i<10;i++){ System.out.print(i); } } }
-
使用Lambda表达式
new Thread( ()-> {...}).start();
使用多线程
import java.text.SimpleDateFormat;
import java.util.Date;
public class Test {
public static void main(String args[]) {
Counter c1 = new Counter(1);
Thread t1 = new Thread(c1);
Thread t2 = new Thread(c1);
Thread t3 = new Thread(c1);
Counter c2 = new Counter(2);
Thread t4 = new Thread(c2);
Thread t5 = new Thread(c2);
Thread t6 = new Thread(c2);
TimeDisplay timer = new TimeDisplay();
Thread t7 = new Thread(timer);
t1.start();
t2.start();
t4.start();
t5.start();
}
}
class Counter implements Runnable {
int id;
Counter(int id) {
this.id = id;
}
public void run() {
int i = 0;
while (i++ <= 10) {
System.out.println("ID: " + id + " No. " + i);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
}
}
}
class TimeDisplay implements Runnable {
public void run() {
int i = 0;
while (i++ <= 3) {
System.out.println(new SimpleDateFormat().format(new Date()));
try {
Thread.sleep(40);
} catch (InterruptedException e) {
}
}
}
}
import java.awt.*;
import java.applet.*;
import java.awt.event.*;
import javax.swing.*;
public class Test extends JApplet
{
MovingShape [] shapes;
public void init()
{
setLayout(null);
setSize(426,266);
shapes = new MovingShape[ 10 ];
for( int i=0; i<shapes.length; i++ ){
shapes[i] = new MovingShape(this);
shapes[i].start();
}
}
public void destroy()
{
for( int i=0; i<shapes.length; i++ )
shapes[i].stopped =true;
super.destroy();
}
public static void main(String [] args) //加入main,使之能当Application应用
{
Frame f = new Frame();
f.setSize(450,300 );
Test p = new Test();
f.add ( p );
f.setVisible( true );
p.init();
p.start();
f.addWindowListener( new WindowAdapter(){
public void windowClosing(WindowEvent e){ System.exit(0); }
});
}
}
class MovingShape extends Thread
{
private int size=100;
private int speed=10;
private Color color;
private int type;
private int x,y,w,h,dx,dy;
protected java.awt.Component app;
public boolean stopped;
MovingShape( java.awt.Component app )
{
this.app = app;
x = (int)(Math.random() * app.getSize().width);
y = (int)(Math.random() * app.getSize().height);
w = (int)(Math.random() * size );
h = (int)(Math.random() * size );
dx = (int)(Math.random() * speed );
dy = (int)(Math.random() * speed );
color = new Color (
(int)(Math.random()*128+128),
(int)(Math.random()*128+128),
(int)(Math.random()*128+128) );
type = (int)(Math.random() * 3 );
}
public void run()
{
while( true ){
if( stopped ) break;
//draw();
SwingUtilities.invokeLater(
new Runnable(){
public void run(){
draw();
}
} );
try{ Thread.sleep(130); } catch( InterruptedException e ){}
}
}
void draw(){
x += dx;
y += dy;
if( x<0 || x+w>app.getSize().width ) dx = -dx;
if( y<0 || y+h>app.getSize().height) dy = -dy;
Graphics g = app.getGraphics();
switch( type ){
case 0:
g.setColor(color);
g.fillRect( x,y,w,h );
g.setColor( Color.black );
g.drawRect( x,y,w,h );
break;
case 1:
g.setColor(color);
g.fillOval( x,y,w,h );
g.setColor( Color.black );
g.drawOval( x,y,w,h );
break;
case 2:
g.setColor(color);
g.fillRoundRect( x,y,w,h,w/5,h/5);
g.setColor( Color.black );
g.drawRoundRect( x,y,w,h,w/5,h/5 );
break;
}
}
}
线程控制
-
启动
start() -
结束
设定一个标记变量,以结束相应的循环 -
暂时阻止线程执行
try{Thread.sleep(1000);}catch(InterruptedException e){}
-
设定线程优先级
setPriority(int priority)方法
MIN_PRIORITY, MAX_PRIORITY, NORM_PRIORITY
后台线程
- 一类是普通线程(非Daemon线程)
若存在非Daemon线程,则程序不会结束 - 一类是Daemon线程(守护线程,后台线程)
普通线程结束了,则后台线程自动终止
使用setDaemon(true);
例如垃圾回收线程是后台线程
import java.util.*;
public class TestThreadDaemon {
public static void main(String args[]) {
Thread t = new MyThread();
t.setDaemon(true);
t.start();
System.out.println( "Main------" + new Date());
try{ Thread.sleep(500); } catch(InterruptedException ex){}
System.out.println("Main End");
}
}
class MyThread extends Thread {
public void run() {
for(int i=0; i<10; i++ ){
System.out.println( i + "------" + new Date());
try{ Thread.sleep(100); } catch(InterruptedException ex){}
}
}
}
线程同步
class TestThreadCount
{
public static int cnt=0;
public static void main(String[] args)
{
final int NUM=50000;
Thread [] threads = new Thread[NUM];
for(int i=0; i<NUM; i++){
threads[i] = new Thread(){
public void run(){
cnt++;
}
};
}
for(int i=0; i<NUM; i++) threads[i].start();
try{ Thread.sleep(3000); } catch(InterruptedException ex){}
System.out.printf("%d %b\n", cnt, cnt==NUM);
}
}
互斥锁
保证共享数据操作的完整性
每个对象都对应于一个monitor监视器,他上面一个成为互斥锁的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象
关键字synchronized用来与对象的互斥锁联系
synchronized用法:
- 对代码片段:
synchronized(对象){…} - 对某个方法
Synchronized 放在方法声明中
public synchronized void push(char c){}
相当于对synchronized(this)表示整个方法为同步方法
class SyncCounter2
{
public static void main(String[] args){
Num num = new Num();
Thread counter1 = new Counter(num);
Thread counter2 = new Counter(num);
for( int i=0; i<10; i++ ){
num.testEquals();
try{
Thread.sleep(100);
}catch(InterruptedException e){
}
}
}
}
class Num
{
private int x=0;
private int y=0;
synchronized void increase(){
x++;
y++;
}
synchronized boolean testEquals(){
boolean ok = (x==y);
System.out.println( x + "," + y +" :" + ok);
return ok;
}
}
class Counter extends Thread
{
private Num num;
Counter( Num num ){
this.num = num;
this.setDaemon(true);
this.setPriority(MIN_PRIORITY);
this.start();
}
public void run(){
while(true){
num.increase();
}
}
}
使用wait()方法可以释放对象锁
使用notify()或notifyAll()可以让等待的一个或所有线程进入就绪状态
class Producer extends Thread {
private CubbyHole cubbyhole;
private int number;
public Producer(CubbyHole c, int number) {
cubbyhole = c;
this.number = number;
}
public void run() {
for (int i = 0; i <10; i++) {
cubbyhole.put(i);
//System.out.println("Producer #" + this.number + " put: " + i);
//try {
// sleep((int)(Math.random() * 100));
//} catch (InterruptedException e) {
//}
}
}
}
class Consumer extends Thread {
private CubbyHole cubbyhole;
private int number;
public Consumer(CubbyHole c, int number) {
cubbyhole = c;
this.number = number;
}
public void run() {
int value = 0;
for (int i = 0; i <10; i++) {
value = cubbyhole.get();
//System.out.println("Consumer #" + this.number + " got: " + value);
}
}
}
class CubbyHole1
{
private int seq;
public synchronized int get() {
return seq;
}
public synchronized void put(int value) {
seq = value;
}
}
class CubbyHole2
{
private int seq;
private boolean available = false;
public synchronized int get() {
while (available == false) ; //dead locked !!!
return seq;
}
public synchronized void put(int value) {
while (available == true) ;
seq = value;
available = true;
}
}
class CubbyHole3 {
private int seq;
private boolean available = false;
public synchronized int get() {
while (available == false) {
try {
wait(); // waits for notify() call from Producer
} catch (InterruptedException e) {
}
}
available = false;
notify();
return seq;
}
public synchronized void put(int value) {
while (available == true) {
try {
wait(); // waits for notify() call from consumer
} catch (InterruptedException e) {
}
}
seq = value;
available = true;
notify();
}
}
class CubbyHole {
private int data[] = new int[3];
private int index = 0;
public synchronized int get() {
while (index <= 0) {
try {
wait(); // waits for notify() call from Producer
} catch (InterruptedException e) {
}
}
index --;
int value = data[index];
System.out.println("Consumer " + " got: " + data[index]);
notify();
return value;
}
public synchronized void put(int value) {
while (index >= data.length) {
try {
wait(); // waits for notify() call from consumer
} catch (InterruptedException e) {
}
}
System.out.println("Producer " + " put: " + value);
data[index] = value;
index ++;
notify();
}
}
class ProducerConsumerStack {
public static void main(String args[]) {
CubbyHole c = new CubbyHole();
Producer p1 = new Producer(c, 1);
Consumer c1 = new Consumer(c, 1);
p1.start();
c1.start();
}
}
也有可能造成死锁互相等待的情况
class DeadLockDemo{
class Worker
{
int id;
public Worker(int id){ this.id=id; }
synchronized void doTaskWithCooperator(Worker other){
try{ Thread.sleep(500); } catch(Exception e){}
synchronized(other){
System.out.println("doing" + id);
}
}
}
void test(){
Worker w1 = new Worker(1);
Worker w2 = new Worker(2);
Thread td1 = new Thread(){
public void run(){
w1.doTaskWithCooperator(w2);
}
};
Thread td2 = new Thread(){
public void run(){
w2.doTaskWithCooperator(w1);
}
};
td1.start();
td2.start();
}
public static void main(String[] args) {
new DeadLockDemo().test();
}
}
并发API
java.util.concurrent包
原子变量
Java.util.concurrent.atomic
AtomicInteger类
getAndIncrement()方法
import java.util.concurrent.atomic.AtomicInteger ;
class AtomicIntegerDemo
{
public static AtomicInteger cnt = new AtomicInteger(0);
public static void main(String[] args)
{
final int NUM=10000;
Thread [] threads = new Thread[NUM];
for(int i=0; i<NUM; i++){
threads[i] = new Thread(){
public void run(){
cnt.getAndIncrement();
}
};
}
for(int i=0; i<NUM; i++) threads[i].start();
try{ Thread.sleep(3000); } catch(InterruptedException ex){}
System.out.printf("%d %b\n", cnt.get(), cnt.get()==NUM);
}
}
线程池
线程池相关类
ExecutorService接口,ThreadPoolExecutor类
Executors工具类
ExecutorService pool = Executors.newCachedThreadPool();
使用其execute( Runnable r)方法
import java.util.concurrent.*;
class ThreadPoolDemo
{
public static void main(String[] args)
{
ExecutorService pool = Executors.newCachedThreadPool();
MyTask t1 = new MyTask(5);
MyTask t2 = new MyTask(7);
MyTask t3 = new MyTask(8);
pool.execute(t1);
pool.execute(t2);
pool.execute(t3);
pool.shutdown();
}
}
class MyTask implements Runnable
{
int n=10;
public MyTask(int n){ this.n=n;}
public void run(){
for(int i=0;i<n; i++)System.out.print(i);
}
}
组件
Swing组件
JComponent是非顶层容器,都是容器,都有add子组件
实现界面的步骤
- 创建组件
- 指定布局
- 响应事件
import javax.swing.*;
import java.awt.*;
public class TestJFrame extends JFrame
{
private JLabel lbl;
public TestJFrame()
{
super("Test JFrame");
lbl = new JLabel("Hello Swing");
//add(lbl);
getContentPane().add(lbl);
setSize(300, 200);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args)
{
new TestJFrame().setVisible(true);
}
}
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class JButtonDemo extends JFrame {
JButton b1 = new JButton("JButton 1");
JButton b2 = new JButton("JButton 2");
JTextField t = new JTextField(20);
public JButtonDemo() {
b1.setToolTipText("Press Button will show msg");
b1.setIcon( new ImageIcon( "cupHJbutton.gif") );
getContentPane().setLayout( new FlowLayout() );
getContentPane().add(b1);
getContentPane().add(b2);
getContentPane().add(t);
setSize(400,300);
setDefaultCloseOperation(EXIT_ON_CLOSE);
ActionListener al = new ActionListener() {
public void actionPerformed(ActionEvent e){
String name =
((JButton)e.getSource()).getText();
t.setText(name + " Pressed");
}
};
b1.addActionListener(al);
b2.addActionListener(al);
}
public static void main(String args[]) {
new JButtonDemo().setVisible(true);
}
}
事件监听器
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TestActionEvent {
public static void main(String args[]) {
JFrame f = new JFrame("Test");
JButton btn = new JButton("Press Me!");
f.add(btn);
ActionListener al = new MyListener();
btn.addActionListener(al);
f.setSize(300, 120);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
class MyListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("a button has been pressed");
}
}
事件监听器是一些事件的接口
接口中含有相关的方法:
MouseMotionListener是对鼠标移动事件的处理的接口,它含有两个重要的方法:
void mouseDragged(MouseEvent e);//处理鼠标拖动的方法
void mouseMoved(MoudeEvent e);//处理鼠标移动方法
事件类中包含有事件相关的信息:
- 事件源(即产生事件的组件)
getSource()
得到的Object可以强制转换成相应的类型 - 事件的具体情况
如MouseEvent的getX(),getY()方法得到鼠标的坐标
KeyEvent的getKeyChar()得到当前的字符
事件适配器
简化实现Listener
注册事件监听器
add xxxx Listener
监听器实现方法
- implements xxxxListener
- Extends xxxAdapter
其中Adapter是Listener的默认实现,每个方法的方法体为空
Adapter可以只Override其中重要的方法
本文地址:https://blog.csdn.net/zhj12399/article/details/112021885
上一篇: 如何选择域名和空间