欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java笔记

程序员文章站 2022-03-06 19:12:04
Java基础知识JAVA特点对象类对象模块化继承性多态程序的分析和设计都围绕JAVA SE类型:Application和Applet程序普通的应用程序Applet程序JAVA程序的基本构成JDK安装后的文件夹Application编辑编译运行程序编译程序运行Applet编辑编译运行工具主要工具常用的工具使用jar打包使用JavaDoc生成文档使用javap输入输出文本界面使用java.util.Scanner类使用java.io包AppCharInOunt.java得到一个字符AppLineInOut.ja...

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(){}
    }
    

    子类便继承了父类的那些功能属性,并且具有子类这些更新的属性

  • 好处:

    1. 更好的进行抽象与分类
    2. 增加代码的重用率
    3. 提高维护性

多态

不同的对象收到一个调用方法可产生完全不同的效果
老师和学生虽然都被一个函数调用却能产生两种不同的打招呼方式

foo(Person p) {p.sayHello();}
foo(new Student());
foo(new Teacher());

程序的分析和设计都围绕

  1. 有哪些对象
  2. 每个类有哪些属性,方法
  3. 类之间的关系(继承,关联)
  4. 对象之间调用方法

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.exe
javac 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的程序三个条件

  1. 是Applet的派生
  2. 含有main();
  3. 在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局部变量时,也必须且只能复制一次
  • abstract类

    • abstract类
      凡是用abstract修饰符修饰的类被称为抽象类
      抽象类不能被实例化
    • abstract方法
      被abstract所修饰的方法叫抽象方法,抽象方法的作用在为所有子类定义一个统一的接口.
      对抽象方法只需声明,而不需实现,即用分号;而不是{}
      一旦某个类中包含了absract方法,则这个类必须声明为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
 */

构造方法的执行过程

  1. 调用本类或父类的构造方法,直至最高一层(Object)
  2. 按照声明顺序执行字段的初始化赋值
  3. 执行构造函数中的各语句

简单的说:先父类构造,再本类成员赋值,最后执行构造方法中的语句

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对象时,要带参数,则使用父类的构造方法

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)
  • 不能访问没有引用到的内存
  • 自动回收垃圾
  1. 传地址 -> 对象

    • 引用类型,引用本身就相当于指针
      可以用来修改对象的属性,调用对象的方法
    • 基本类型:没用对应的
      如交换两个整数
      void swap(int x, int =y) {int t = x; x = y; y =t; }
      int a = 8, b = 9; swap( a, b);
      一种变通的办法,传出一个有两个分量x,y的对象
  2. 指针运算 -> 数组
    *(p + 5)则可以用args[5]

  3. 函数指针 -> 接口,Lambda表达式
    求积分,线程,回调函数,时间处理

  4. 指向结点的指针 -> 对象的引用

    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;
    	}
    }
    
  5. 使用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();
            }
    	}
    }
    

自定义异常

  1. 将当前捕获的异常再次抛出
    throw e
  2. 重新生成一个异常,并抛出,如:
    throw new Exception(“some message”);
  3. 重新生成并抛出一个新异常,该异常中包含了当前异常信息,
    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)

多线程

进程:一个程序的执行
线程:程序中单个顺序的流控制
一个程序中可以含有多个线程

创建线程

  1. 通过继承Thread类创建线程

    class MyThread extends Thread{
        public void run(){
            for(int i=0;i<100;i++){
                System.out.print(" "+i);
            }
        }
    }
    
  2. 通过向Thread()构造方法传递Runnable对象来创建线程

    class MyTask implements Runnable{
        public void run(){
            
        }
    }
    
    Thread thread = new Thread(mytask);
    thread.start();
    
  3. 使用匿名类

    new Thread(){
        public void run(){
            for(int i=0;i<10;i++){
                System.out.print(i);
            }
        }
    }
    
  4. 使用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);//处理鼠标移动方法

事件类中包含有事件相关的信息:

  1. 事件源(即产生事件的组件)
    getSource()
    得到的Object可以强制转换成相应的类型
  2. 事件的具体情况
    如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

相关标签: java