Professional Documents
Culture Documents
根据ppt上讲的顺序去敲代码,有不懂得可以查帮助文档API
1、java概述
sun公司Green项目 hotjava浏览器
2、java特点
简单易学:没有c和c++的指针,内存申请和释放
安全性高:强类型,垃圾回收机制,禁止非法内存访问。
跨平台:作为一种网络语言,其源代码被编译成一种结构中立的中间文件格式。只
要有Java运行系统的机器都能执行这种中间代码。java源程序被编译成一种与机器无关
的字节码格式,在Java虚拟机上运行。
多线程的。即能够使得一个程序同时执行多个任务。
3、java虚拟机 JVM
4、JVM的平台相关性:java源代码与字节码是与机器无关的,故在装有不同操作系统的
机器上,需要有专门为该操作系统开发的JVM,JVM是与机器有关的。
5、java的应用领域
1、J2SE ,主要用来开发桌面应用软件
2、J2ME,嵌入式开发,像手机里的软件,掌上电脑
3、J2EE,属于网络编程,JSP等,
6、怎么学JAVA语言。
《java就业培训》张孝祥,
《java学习笔记》林信良
张孝祥,孙鑫,张利国,马士兵
在eclipse中查看java源码首先在这个网站下载源码或者直接复制此链接就可下载
7、学习目标,了解程序语言及发展历史,掌握语法规则,掌握常用类的使用掌握编程
http://download.java.net/openjdk/jdk7/promoted/b147/openjdk-7-fcs-src-b147-27_jun_2011.zip
逻辑思维能力:会看懂程序,会调试程序,理解并应用面对对象的设计思想。为将来学
下载源码压缩包后,直接拷贝到C:\Program Files\Java\jre1.8.0_251\lib下面
在eclipse中按快捷键F4,随便点击一个类或方法,在主编辑区出现一个页面,找到changed
习J2EE做准备。 attached
source并点击,会弹出对话框,选择external location并按照路径找到刚刚拷贝的压缩包
8、环境变量的设置:2016年2月26日15:03:45
为什么要设置path:1、在dos的任何目录下我们都可以运行系统自带的命令; 2、
我用的是jdk-9;按照右面配置即可。但是!也可以不用先定
义系统变量JAVA_HOME=jdk路径,之后再使用%JAVA_HOME%命
令来获取其路径。不如直接到jdk目录下,然后直接生成其路
径复制过来就可以。各路径之间用英文分号“ ;”隔开。本来
就有的系统变量Path和自建的系统变量CLASSPATH方法同上。
下面的1234步骤是jdk-9下面版本的配置方式。
要想在dos下运行用户自己的程序,则必须进入到改程序的当前目录下方课运行; 3、
如果希望在dos的任何目录下都可以运行自己创建的程序,则需要我们自己手动设置操
作系统自带的环境变量path.
path的设置:操作系统是利用path变量来寻找当前程序所存放的路径,并且以最先
找到的为准。路径与路径之间用分号;分开。
java语言运行
————————————————————————————————
System.out.println("我能学好Java语言!");
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
c语言编译后exe运行:
9、classpath的设置。
操作系统是利用classpath变量来寻找当前后缀为class的字节码文件所存放的路
径,并且以最先找到的为准。
10、常见dos命令。
cd \ 表示进入当前根目录下 单击Tab键可自动补齐目录名字和目录下的文件名
cd A\B\C 表示当前目录下的A文件夹下的B文件夹下的C文件夹下面
E: 进入E盘根目录
dir 查看文件夹下文件信息
cls 清屏 javac命令编译生成与平
台无关的字节码程序,
javac name.java 编译java文件 名字为类名,扩展名
为.class
java name 运行java文件,即打开.class文件,
只能是name不能是name.class哎!
编译时写文件名,运行时写文件中的类名。故文件的名字和类名最好一样。
11、Java语言的基本要素——标识符
程序员对程序中的各个元素加以命名时使用的命名记号称为标识符(identifier)
包括:类名、变量名、常量名、方法名、……
标识符是以字母,下划线(_)美元符($)开头的一个字符序列,后面可以跟字
母,下划线,美元符,数字。
12、数据类型
基本数据类型:
使用8421码辅助记忆
数值型(整数类型(int,byte,short,long)
,浮点类型(float,double)
)
字符型(char)
布尔型(boolean)
引用数据类型:
(类(class)
,接口(interface)
,数组)
;
13、输出数据的格式控制:
%f(float,double)
%c(char)
%x,%X,%#X,%#x (int long int )
%s (string)
14、常量
(1)整型常量:十进制,十六进制,八进制
一个常量整数默认是int类型,如果数字过大,则必须在末尾加L,否则会报错。
例:long i = 5678678956789;//error
long i = 5678678956789L;//ok
(2)浮点型:一个实数默认是double类型。如果希望一个实数是float类型,可以在
数字后面加f(F)
。将一个double类型数值付给float类型变量,编译时会报错。
(3)字符常量:
必须用单引号括起来;Java中字符和字符串都用Unicode编码表示;在Unicode
编码中一个字符占两个字节。‘a'‘\n' '\uxxxx' '\u4e2d'代表Unicode编码下的字符{中}
特殊字符的常量表示法
'\\' '\n'
(4)布尔类型:用boolean表示,不能写成bool;布尔型数据只有两个值true和false,
且他们不对应于任何整数值。
定义:boolean b = true
只能参与逻辑关系运算:&& || == != !
————————————————————————————
class BiJiao
{
public static void main(String[] args)
{
float a = 12.45f;
double b = 45.5;
boolean e;
boolean d;
15、不同类型变量的字节。
( 一个字节byte 八位bit )
16、不同类型的变量相互转换:一般低字节可以转换成高字节。高字节转换成低字节必须强制转换。
byte b = 10;//1个字节
int i = 6;//4个字节
i = b;//ok b = i;//error 会丢失数据
b = (byte)i;//ok 强制类型转化
//b = i;//本语句错误,上面的(byte)i并没有改变i本身的数据类型。
17、算术运算符:
(1)“+”可以表示数值的相加,字符串的联接,也能把非字符转换成字符串。
System.out.println('a'+1);与System.out.println(""+'a'+1);
结果 98 a1
(2)除法运算符(/)
跟C语言一样。
(3)取余运算符(%)
java中允许取余取余运算符的被除数和除数是实数,
(与C/C++不同)。但所得余数
的正负只和被除数相同。
(4)逻辑与,逻辑或。
跟C语言一样。
(5)位运算符:
(0表示正数,1表示负数)
&(按位与)把两个数字所有的二进制位相与:1&1=1,1&0=0,0&0=0;0&1=0
|(按位或)把两个数字所有的二进制位相与:1|1=1,1|0=1,0|0=0;0|1=1
~(按位取反)把一个数字的所有二进制位取反。~1=0 ~0=1
^(按位异或)把两个数字的所有二进制位异或1^1=0,1^0=1,0^0=0;0^1=1
————————————————————利用异或实现换值————————
import java.util.Scanner;
public class VariableExchange
{
public static void main(String[] args)
{
Scanner scan = new Scanner(System.in);
System.out.println("请输入A的值");
long A = scan.nextLong();
System.out.println("请输入B的值");
long B = scan.nextLong();
System.out.println("A="+A+"\tB="+B); 运行结果:
请输入A的值
System.out.println("执行变量互换..."); 3
A = A ^ B; 请输入B的值
5
B = B ^ A; A=3 B=5
A = A ^ B; 执行变量互换...
System.out.println("A="+A+"\tB="+B); A=5 B=3
}
}
—————————————————————————————————
import java.util.Scanner;//是util而不是until
public class LeapYear
{
public static void main(String[] args)//后面不应该加分号
{
Scanner scan = new Scanner(System.in);
System.out.println("请输入一个年份:");
long year = scan.nextLong();
if(year % 4 == 0 && year % 100 !=0||year % 4 == 0)
System.out.print(year + "年是闰年!");
else
System.out.print(year + "年是不是闰年!");
运行结果:
} 请输入一个年份:
2020
} 2020年是闰年!
+++++++++++++++++++++++++++++++++++++++++++++++++++++++ 电子书113
>>(右移)与 C/C++不同,对于有符号数,在右移时,符号位将随同移动,当为正数
时,最高位0,最高位补零,而为负数时,最高位为1,最高位补1。移位能让用户实现
整数除以或乘以2的n次方的效果。
>>>(右移)无论最高位是0还是1,左边移空的都补为零。
(6)自增自减
——————————————————————
class Triangle //启动类 模拟出事物
{
int a, b, c;
int zhouchang()
{
return a + b + c;
}
double area()
{
double p = 1.0*(a+b+c) / 2;
return Math.sqrt(p * (p-a) * (p-b) * (p-c));
}
}
class TestTriangle
{
public static void main(String[] args)
{
Triangle t = new Triangle();
t.a = 3;
t.b = 4;
t.c = 5;
19、面向过程设计思想
优点: 1、分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现。
2、以算法为核心,
3、自顶向下设计,要求一开始必须对问题有很深的了解
4、将大问题转化为若干小问题来求解
5、表现形式:用函数来作为划分程序的基本单位
6、直接面向问题。
缺点:数据和操作分离开,对数据与操作的修改变得很困难;数据的安全性得不到保证;
程序架构的依赖关系不合理。
20、面向对象的设计思想
1、确定该问题由哪些问题组成!先用类模拟出该事物
2、通过类间接解决问题。
21、类:把一类事物静态属性和动态可以执行的操作组合在一起所得的这个概念就是类
类是抽象的,用来模拟一类事物,是一个概念,一旦定义了,类的概念就永远存在
22、对象:类的一个个体;具体的实实在在存在的事物;生命周期是短暂的。
左图:内部类N可以使用所有的
访问控制符,外部类M只能使用
访问控制符public或者什么都不
加。类A这种写法是错误的。
类
对象
类的定义:
class Person
{
int age;
void shout()
{
System.out.println("oh,my god!"+ age);
}
}
对象名.属性(成员变量)// 访问对象的属性
age是类的属性,也叫类的成员变量,也叫字段,也叫域 对象名.成员方法名()// 访问对象的方法
aa.i和aa.j叫做属性引用。
shout是类的方法,也叫类的成员函数 aa.f()叫做方法引用
访问对象的属性和方法就叫做引用。
shout方法可以直接访问同一个类中的age变量。 只有对象引用特殊点
A aa = new A();其中aa叫做类A引用类型的
变量,存放在栈空间,用来指向new出来的A
23、内存分配 对象的对象引用。
——————————类对象实例 1——————————————————
class A
{
int i;
int j;
}
class TestMemo
{
C++中new的用法格式为:
public static void main(String[] args) int* P = new int();
{ 和C中malloc对比着看:
A aa = new A();//(A *)malloc(sizeof(A))int* P = (int *)malloc(sizeof(int));
//new A();在堆中动态分配一块区域,被当作了A对象
//aa本身的内存是在栈中分配的
//堆中内存的地址付给了aa
//aa指向堆中的内存,aa代表了堆中的内存。
//aa.i代表aa静态指针变量所指向的动态内存中的A对象这个i成员
//aa.j代表aa静态指针变量所指向的动态内存中的A对象这个j成员
对象名.属性(成员变量)// 访问对象的属性
对象名.成员方法名()// 访问对象的方法
aa.i和aa.j叫做属性引用。
aa.f()叫做方法引用
访问对象的属性和方法就叫做引用。
只有对象引用特殊点
A aa = new A();其中aa叫做类A引用类型的变量,存放在栈空间,用来指向new出来的对象。
aa.i = 10;
aa.j = 20;
System.out.printf("%d, %d\n",aa.i, aa.j);
}
运行结果:
} 10, 20
+++++++++++++++++++++++++++++2016年2月26日23:47:30 11未完
栈(静态分配)中指针变量aa本身占四个字节,aa是指针变量,只能存放对应类型变量的地址。堆(动态分
配)中分配的一块内存区域被当做A对象,并把这块内存区域的首地址送到指针变量aa中,则aa指向堆中这块
的内存,则表示aa指向A对象,在堆中动态分配的内存块并没有名字,aa指向这块内存,则aa就是他的名字。
aa.j中aa本身的栈内存不含有j这个数据成员,aa是指针变量,只能存放对应类型变量的地址。则aa.j表示,
aa指针变量所指向的堆里面的那块内存A对象的成员j。JAVA中的aa.j等于C语言中的(*aa).j也即aa.j==
(*aa).j。JAVA把C语言指针的*砍掉了。
若是完全等同于C语言应该是这样的A *aa = (A*)malloc(sizeof(A));
JAVA中为A aa = new A;
data segment:是static静态变量和字符串常量的存储区
在创建类的时候,类的属性和方法若是static静态的,其属于类本身。类的属性若是static修饰的,则会在
data segment分配存储空间(对象之间共用),没通过类创建对象时,不是private私有的情况下外部直接就
可以通过'类名.属性'访问使用,不加static则只有在通过类创建对象时才会在堆中为对象分配存储空间,
每个对象之间的属性是不一样的不共用。
类的方法若是加上static修饰放在data segment区(对象之间共用),没创建类的对象时,不是private私有
的情况下外部可以直接通过'类名.方法'访问使用。否则不加static则只有在通过类创建对象时,为类的方
法在code segment区为其分配存储空间(对象之间共用)之后才能被访问。this指向当前调用此方法的对象
static静态方法不能访问非静态成员,非静态方法可以访问static静态成员,上述适用于:类的属性和方法
的内部相互访问和外部访问。因为非静态的要有对象才能被访问,所以静态方法不能访问非静态成员。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
———————类对象实例 2————————2016年2月27日21:39:59
class A
{
int i;
int j;
}
class TestMemo
栈
{ 堆
public static void main(String[] args)
{
new A
A aa1 = new A();
A aa2 = new A();
new A
aa.i = 50;
aa.j = 80;
System.out.printf("%d, %d\n",aa1.i, aa2.i);
}
}
结论:一个new A()生成的对象是不一样的。
++++++++++++ 结果50 80 +++++++++++++++++++++++++++++++++
——————— 类对象实例 3 ——————————————————
class A
{
int i;
int j;
}
class TestMemo
{
public static void main(String[] args)
{
A aa1 = new A();
aa1中保存new出来的A对象的首地
A aa2 = aa1;//最后aa1和aa2同时指向堆中的一个对象。址,A aa2 = aa1;则aa1中保存的
地址值赋值给了aa2,则aa1和aa2
aa1.j = 50; 内部都保存了A对象的首地址,则
System.out.printf("%d\n",aa2.j);// 其都指向堆中的A对象
} 运行结果:
} 50
访问控制符确切的应该叫外部直接访问控制符,类的访问控制符在内部失效,内部透明
private私有的不能被外部直接访问,public公有的可被外部直接访问
class Triangle
{
private int a, b, c;//如果不加访问控制符private,将默认为default,可以被
任何一个对象去使用。
int zhouchang()
{
return a + b + c;
}
double area()
{
double p = 1.0*(a+b+c) / 2;
return Math.sqrt(p * (p-a) * (p-b) * (p-c));
}
}
class TestTriangle_2
{
public static void main(String[] args)
{
Triangle t = new Triangle();
t.set(3, 4, 5);
System.out.printf("%d %f\n", t.zhouchang(), t.area());
}
运行结果:
} 12 6.000000
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
——————类的构造函数——————————————————14
class A 不要叫构造函数
要叫构造方法
{
private int i;
private int j;
public A()
{
//System.out.printf("嘿嘿!\n\n");
A aa = new A();//在对象被创建时看到A()没,这个
就是一个函数的形式,这就是一种方法,不过他比较
特殊叫构造方法。
}
//构造函数
public A(int a, int b)
{
i = a;
j = b;
System.out.printf("无参构造函数被调用了!\n");
}
class TestConst_2
{
public static void main(String[] args)
{
创建对象aa时,他会调用类A的有参数
A aa = new A(1, 2); 构造函数public A(int a, int b)
//A aa2 = new A(1,2,3); //error
A aa3 = new A(); 创建对象aa3时,他会调用类A的无参数构造函数public A()
若是类A中没有无参数的构造函数,系统会默认自动创建一个无参数的
// 构造函数public A(),但前提是类A中没自己手动创建别的构造函数。
// //System.out.printf("%d %d\n", aa.i, aa.j);
// aa.show(); 任何一个类的对象被生成时,一定会调用其中的某个构造方法
}
}
————————————————————2016年2月27日23:16:04
管理与技术
————————————————————————2016年2月29日14:47:00
class B
{
public int i = 10;
class M
{
public static void main(String[] args)
{
B bb1 = new B();
B bb2 = new B();
bb1.i = 20;
bb2.show();//结果为10
//bb1 = bb2;//把bb2的地址赋值给了bb1
//bb1.i = 20;
//bb2.show();//结果为20.看下面的图。
}
}
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
函数的重载:同名的函数通过不同的形参做类似的事情,就叫做函数的重载。
函数重载要求:函数的形参个数,形参顺序,形参数据类型,三个至少有一个是不一样
的 函数的重载:重要的事情说三遍,形参形参形参是形参的个数或顺序或数据类型不同才行
如果两个函数只是函数的返回值不一样,其他的一样,就不构成重载,编译时会出错。
class TestOver
{
static int add(int a, int b)
{
return a + b;
}
class A
这个i是类的属性,如果不初始化,Boolean类型默认是
{ false,数值型默认为0.当其在函数内部属于局部变量,局
public int i = 2; 部变量不初始化不能被使用,会报错
public boolean flag = true;
class Testconst_2
{
public static void main(String[] args)
{
A aa = new A(88, false);
aa.show();
}
} 运行时报错:The local variable k may not have been initialized
结论:系统会先执行定义时赋的初值,然后再执行构造函数中赋的初值。如果在定义的
时候不初始化,则他的值是系统自动分配好的默认值。
+++++++++++++++++++++++++ 结果 88 false +++++++++++++++++++
this 是一个系统隐含的指针被自动附加在非静态的成员函数参数列表中。
当前时刻,哪个对象调用该函数,那么this就指向当前调用该函数的对象,系统会
自动在该函数的参数列表中添加一个隐藏的指针,并且把调用该函数的对象的地址赋给
this指针,这样一来,在函数的内部通过this就可以访问当前正在调用该函数的对象的
成员
方法区是共享的又叫非堆,感觉还是描述
成存储在代码段code segment比较准确
右图运行结果
左边这图只是 i = 10
图解指针过程 i = 20
静态函数内部,没有this指针。因为类的静态属性和方法属于类本身,非静态属性和
方法属于类的对象。
关键字this代表当前正在调用该方法的那个对象,具体可分为两种情况:1、在普
通方法中,this代表方法的调用者,即本次调用了该方法的对象。2、在构造方法中,
关键字this代表了该方法本次运行所创建的那个新对象。
——————————————————————————————
class A
{
private int i;
public A(int i)
{
this.i = i;//将形参 i 赋给该构造方法本次运行所创建的那个新对象的i数据成员
}
public void show()
{
System.out.println("i = " + this.i); //this表示当前时刻正在调用show方法的对象
//this可以省略
}
}
——————————————————————————
/*
2016年3月5日10:01:20
本程序证明了:
静态方法不能访问非静态成员 适用于:类的属性和方法的
非静态方法可以访问静态成员 内部相互访问和外部访问。
因为非静态的要有对象才能
*/ 被访问,所以静态方法不能
访问非静态成员
class A
{
private static int i = 10;
public int j = 99;
class TestStatic_5
{
public static void main(String[] args)
{
A aa = new A();
//aa.g();
aa.f();
//A.g(); //error,无法从静态上下文中引用非静态方法
}
} 运行结果:FFFF
data segment:是static静态变量和字符串常量的存储区
++++++++++++++++++++++++++++++++++++++++++++++++++
在创建类的时候,类的属性和方法若是static静态的,其属于类本身。类的属性若是static修饰的,则会在
data segment分配存储空间(对象之间共用),没通过类创建对象时,不是private私有的情况下外部直接就
可以通过'类名.属性'访问使用,不加static则只有在通过类创建对象时才会在堆中为对象分配存储空间,
每个对象之间的属性是不一样的不共用。
类的方法若是加上static修饰放在data segment区(对象之间共用),没创建类的对象时,不是private私有
的情况下外部可以直接通过'类名.方法'访问使用。否则不加static则只有在通过类创建对象时,为类的方
法在code segment区为其分配存储空间(对象之间共用)之后才能被访问。
static静态方法不能访问非静态成员,非静态方法可以访问static静态成员,上述适用于:类的属性和方法
的内部相互访问和外部访问。因为非静态的要有对象才能被访问,所以静态方法不能访问非静态成员。
因为类的静态属性和方法属于类本身,非静
态属性和方法属于类的对象,只有对象被创
建时才会分配内存。假如类的属性是静态
的,那么你通过此类创建十个对象,这十个
对象的静态属性是共用一个属性,只有这一
个属性,不是十个属性。如果类的属性是非
静态的,那么通过此类创建十个对象,就会
有十个属性。每个对象都各有自己的属性。
因为类的静态属性和方法属于类本身,非静
态属性和方法属于类的对象,只有对象被创
建时才会分配内存。假如类的属性是静态
的,那么你通过此类创建十个对象,这十个
对象的静态属性是共用一个属性,只有这一
个属性,不是十个属性。如果类的属性是非
静态的,那么通过此类创建十个对象,就会
有十个属性。每个对象都各有自己的属性。
通过类只能生成一个对象的方法
类,对象,方法,属性,
++++++++++++++++++++++++++++++++
继承extends:利用继承可以较好的模拟出现实世界事物之间的关系。为多态创造条件。
——————————————————————
/*
2009年5月31日14:59:26
本程序证明了:
1、 子类内部可以访问父类非私有的成员
私有成员无法被子类方法访问
2、 通过子类对象名只能访问从父类继承过来的非私有成员
总结:
私有不能被继承
私有物理上已经被继承过来,只不过逻辑上程序员不能去访问它
因此继承必须慎重,否则会浪费内存
*/
class A{
public int i;
protected int j;
private int k;
g();
b();
//s(); // error 私有方法不能被继承
}
}
class M{
public static void main(String[] args){
B bb = new B();
bb.i = 20;
bb.j = 30;
//bb.k = 40;//error k可以在B中访问private
bb.b();
bb.g();
//B.g();//无法从静态上下文中引用非静态 方法
//bb.s(); //error
//bb.k = 22;
}
}
+++++++++++++++++++++++++++++++++
java只支持单继承,不允许多重继承。单继承就是一个类只能有一个父类。多继承就是
一个类可以有多个父类。可以有多层继承,即一个类可以继承某一个类的子类,如类B
继承了类A,类C继承类B,那么类C也间接继承了类A。
非私有
子类可以继承父类所有的成员变量和成员方法,但子类永远无法继承父类的构造方法,
在子类的构造方法中可使用语句super(参数列表)调用父类的构造方法。
++++++++++++++++++++++++2016年3月5日11:54:49 28
————————————————2016年3月5日 14:21:47
子类访问父类成员的三种方式
在子类内部访问,通过子类对象名访问,通过子类的类名访问。经验证子类无法通过以
上三种方式访问父类的私有成员,所以,得出结论,私有成员无法被子类继承。
————
super: 在子类的构造方法中可使用语句super(参数列表)调用父类的构造方法。super(参数列表)必
须在构造方法的第一行.
—————————
—class A
{
A()
{
System.out.println("AAAA");
}
A(int i){}
}
class B extends A
{
B()
{
super(2); //如果把该语句注释掉的化,则编译器默认的是自动隐含调用super();
//但如果父类没有无参的构造函数,则会报错
//一个子类的构造函数中只能出现一个 super(....)
System.out.println("BBBB");
}
}
class C extends B
{
C()
{
//int k = 10; //如果该语句生效 则会出错,因为会导致super()语句不是构造函数的
//第一条语句
//如果显示写出来的话,编译器要求该语句前面不能加任何语句,也就是说该
//语句必须保证是第一条语句
// super()也可以改为super(2); 但前提是父类必须有带一个参数的构造函数,
//否则也会报错
//如果把35行改为 super(2); 编译时就会报错!
System.out.println("CCCC");
}
}
class TestSuper_1
{
public static void main(String[] args)
{
C cc = new C();
//System.out.println("Hello World!");
}
}
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
总结:
1、每个子类构造方法的第一条语句,都是隐含地调用super(),如果父类没有这种
形式的构造函数,那么在编译的时候就会报错。
2、如果显示的写出super();语句,则必须保证该语句是第一条语句,否则会出错
3、super();如果不写,则编译器会自动添加,所以此时如果父类没有无参的构造函
数就会出错
4 、 既 可 以 显 示 写 super(); 前 提 是 父 类 必 须 有 无 参 的 构 造 函 数 也 可 以 显 示 写
super(实参); 前提是父类必须有带参的构造函数
5、调用父类的构造函数的语句必须借助于super,不能直接写父类的类名,这与C++
不同
6、一个子类的构造函数中只能出现一个 super(....)
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
重写父类方法:是指在子类中重新定义父类中已有的方法
重写方法必须和被重写方法具有相同的方法名词、参数列表和返回值类型
子类中不允许出现与父类同名同参但不同返回类型的方法,如果出现,编译时会报错
覆盖方法时,不能使用比父类中被覆盖的方法更严格的访问权限。重写方法不能低于被重写的方法的访问权限
————————————————————————- super也能调用父类的其他方法和属性
class A{ 如super.f()
super.i
//public void f(){
// System.out.printf("AAAA\n");
//}
class B extends A{
public void f(){
super也能调用父类的其他方法和属性
//super.f(); //调用从父类继承过来的f方法 如super.f()
f(10); super.i
System.out.printf("BBBB\n");
}
}
———————————————————2016年3月7日06:23:02
class Human{
private String name;
private int age;
public Human()//不用加分号
{}
定义:同一代码可以随上下文的不同而执行不同的操作,俗称多态。
子类对象可以直接赋给父类引用,但父类对象在任何情况下都不可以直接赋给子类引
用。 父类是animal,子类是dog/cat
dog是animal,animal却不一定就是dog A aa = new B(); 父类引用aa,子类对象new B()
通过父类的引用只能访问子类对象从父类继承过来的成员
通过父类引用不能访问子类对象所特有的成员
父类引用永远不可能直接赋给子类引用(只有在父类引用本身指向的就是一个子类对象
时,才可以把父类引用强制转化为子类引用,其他情况下不允许把父类引用强制转化为
子类引用) A aa = new B();//步1:父类引用aa,子类对象new B(),父类引用指向子类对象
B bb = (B)aa;//步2:经过上面步1后才能将父类引用强制转化为子类对象
(B)aa == new B();
同样的语句,不一样的执行结果
结果为:AAAA
BBBB
多态和指针
虽然父类aa指向子类bb,但编译器任然认为aa是父类
通过父类引用不能访问子类对象所特有的成员
子类对象可以直接赋给父类引用,
但父类对象在任何情况下都不可以直
接赋给子类引用。
————————————————————————
/*
2009年2月11日17:27:54
父类引用永远不可能直接赋给子类引用
注意:
只有在父类引用本身指向的就是一个子类对象时,才可以把父类引用强制转化
为子类引用
其他情况下不允许把父类引用强制转化为子类引用
*/
class A
{
}
class B extends A
{
}
抽象类:通常用来作为一个类族的最顶层的父亲,用最底层的类来表示具体的事物。
最顶层的父类
abstract 抽象类不一定有抽象方法,有抽象方法一定有抽象类。
————————————————————————
//有抽象方法的类一定是抽象类
abstract class A
{ public void f();这样也叫抽象方法,没有方法体
abstract public void f(); //没有方法体的方法叫做抽象方法, 抽象方
法要求末尾必须得加分号,前面必须得加abstract
}
//抽象类不一定有抽象方法
abstract class B
{
public void g()
{
}
}
class B extends A
{
public void f()
{
System.out.printf("BBBB\n");
}
}
抽象类不能直接new出一个对象,但是可以创建一个指向对象
的一个抽象类的引用类型的变量aa,A aa;
多态
类的对象,所以18行error, 本行OK
aa = bb;
aa.f();
}
}
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
final关键字可以修饰:整个类,类中的若干个属性,类中的若干个方法。
如果认为一个类已经很完美了不需要子类再去继承的时候可以在前面加final。
修饰类中的若干个属性时,表示该属性必须被赋值,并且只能被赋一次值。 常量只读
修饰方法时,表示该方法可以被子类继承,但不可以被重写。
————————————————————————
class A
{
final public int i = 10; //常变量 和C语言中的const功能一样,值不可变,为只读
public A()
{
i = 10;
}
class TestFinal_1
{
public static void main(String[] args)
{
}
}
+++++++++++++++++++++++++++++++++++++++++
class A
{
final public void f() //如果在public前面加final,则编译时就会报错
{
System.out.println("AAAA");
}
}
创建接口时,接口中的方法不允许有方法体
class B extends A
{
// public void f()
// {
// System.out.println("BBBB");
// }
}
定义:就是抽象方法和常量值的集合。从本质上看,接口就是一种特殊的抽象类
格式:[public] interface interface name [extends]
一个类可以在继承一个父类的同时实现一个或多个接口,但extends关键字必须用在
implements之前。
class T extends A implements It3,It4{}
接口可以实现不相关类的相同行为,可以实现多继承,从一定程度上弥补了类只能单继
承的缺陷。
————————————————————————
class A
{
int i;
public class E
{
public static void main(String[] args)
{
A aa = new A();
//aa.g(99);
aa.show();
}
}
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
面向对象大纲:
封装
访问控制符:只有private的不能在外部访问,类内部访问控制符是透明的
构造方法:定义:名字和类名一样,无返回值。
注意事项:一个类对象只能调用一个构造方法,一个类至少有一个构造方
法,如果自己定义了构造方法,编译器将不在提供默认的构造方
法。
this:一个对象只含有属性的空间,n个对象共用一份方法的拷贝。
static:
继承:java只允许单继承,私有成员无法被继承。
重写:方法名和参数列表和返回值必须一样。访问权限不能过低。
多态
++++++++++++++++++++++++++++++++++++++++2016年3月7日11:23:21 39
包:javac -d . 文件名.java
package zhangsan.lisi.TestPackage先检测当前目录下是否有zhangsan/lisi这个
包(文件夹)
,如果有,在监测该包下是否有zhangsan.lisi.TestPackage这个类,如果
没有,编译器将再去classpath设置的路径中依次寻找。如果都查找失败,则运行时出
错。
同包和不同包类的相互访问。
在同一个包中,只有私有的不能被另一个类访问,也只有私有的不能被访问
在不同包没有任何关系的两个类,只有public类的public成员才可以被另一个包中
的类访问。
在不同包中有继承关系的两个类,只有public类的public成员和public类的protected
成员可以被另一个包中的子类在内部使用,但在子类的外部,通过子类对象名只能访问
父类的public成员。
——————————————————————2016年3月8日06:28:18
——————
package zhangsan.lisi;
public class A
{
public void g()
{
System.out.printf("Hello World!\n");
}
protected void b()
{
System.out.printf("Hello JAVA!");
}
}
不同包的类
访问的三种方法
========================================
package com.ruide;
import zhangsan.lisi.*;
class B extends A{
public void f(){
g();//ok
b();//ok, 在 子 类 内 部 可 以 访 问 从 另 一 个 包 继 承 过 来 的 父 类 的 public 和
protected成员。
}
}
class M{
public static void main(String[] args) {
B bb = new B();
bb.f();//ok
bb.g();//ok
//bb.b();//error,不能访问protected。
}
}
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 45
归档工具jar包的生成
作用:发布和使用类库,便于资源的组合和管理
DOS下的命 格式:jar cvf 要生成的包名.jar *
令格式
生成后打开用解压软件打开。
如何使用jar包中的类
import zhangsan.lisi.A;//注意路径后面的分号;
**** 异常(Exception)是程序运行过程中发生的事件,该事件可以中断程序指
令的正常执行流程。 出现了异常且没有异常处理语句则整个程
序只会执行到异常那一句,其他语句都不
会被执行。如果有异常处理语句,执行完
————————————————————
异常处理语句会接着执行后面的语句。
class A{
int divide(int a, int b) {
int m;
//System.out.printf("22222\n");
m = a / b;
//System.out.printf("11111\n");
return m;
}
}
//aa.divide(6, 0);
try{
aa.divide(6,0);//23行 写在try中异常才能被捕获到
异常处理语句
} ArithmeticException是异常类
型的一种,要是不知道是什么
catch (ArithmeticException e) //e用来接收23行抛出的异常对象 类型的异常就用Exception
{
e.printStackTrace(); //可以简单理解为 输出该异常的具体信息
System.out.printf("除零错误, 你的程序出错啦! 除数不能为零!\n");
}
System.out.printf("道可道非常道!\n");
}
}
++++++++++++++++++++++++++++++++++++++++++++++++ 49 2016年3月8日10:45:33
++++++++++++++++++++++++++++++++++++++++++2016年3月9日08:00:50 51
运行结果:
java.lang.ArithmeticException: / by zero
at helloworld.A.divide(helloworlda.java:5)
at helloworld.helloworlda.main(helloworlda.java:23)
除零错误, 你的程序出错啦! 除数不能为零!
道可道非常道!
printStackTrace方法的介绍
异常的分类:
error是系统的错误,程序员无法处理这些异常
ArithmeticException是异
常类型的一种,要是不知 Exception是程序员可以捕获并处理的异常。
道是什么类型的异常就用
Exception RuntimeException的子类异常,是可以处理也可以不处理的异常
凡是继承自Exception但又不是RuntimeException子类的异常必须捕捉并处理。
异常的处理步骤:
Finally的作用
无论try所指定的程序块中是否抛出异常,也无论catch语句的异常类型是否与所
抛弃的异常的类型一致,finally中的代码一定会得到执行
finally语句为异常处理提供一个统一的出口,使得在控制流程转到程序的其他部
分以前,能够对程序的状态作统一的管理
通常在finally语句中可以进行资源的清除工作。如关闭打开的文件,删除临时文件
int div(int a, int b) throws Exception
{
自定义异常
}
public static void main(String[] args){
exa aa = new exa();
throw try
表示方法内抛出某 {
用来抛出异常
种异常对象(只能是 aa.div(6, 0);
一个) }catch(Exception e)
格式:throw new 异常名(参数)
{
e.printStackTrace();
}}
throws 抛出异常类
throws在方法后边声明异常,其实就是自己不想对异常
void f() throws A 做出任何的处理,告诉别人自己可能出现的异常,交给
{ 别人处理;
……
注意:方法名后面跟上 throws Exception 证明这个方
} 法里的语句可能会发生异常,注意是可能!在别处如果
调用这个方法时,就必须也抛出异常或者用try catch
处理。 throws是可以单独使用的。
throws可以单独使用,throw不可以单独使用,必须搭
配try catch,或者throws。若程序执行到throw
exception 语句,则后面的语句不会再执行。
package hello;
class exa
{
int div(int a, int b) throws Exception//声明方法可能抛出异常类Exception
{ 异常类进行处理
建议:对throws出的所有异常进行处理
if(0 == b)
{ 如果一个方法内部已经对throws进行处理了,就不用再处理。
throw new Exception("chu shu bu neng wei ling");//29行throw方法内抛出异常对象
} ————————————————————————————————
int sumclass
= a/b;
DivisorIsZeroException extends Exception
return {sum;
} public DivisorIsZeroException(String errorMessage)
} {
public class throwa super(errorMessage);
{ }
public static
} void main(String[] args)
{
exa aa = new exa();
class A
try {
{ int divide(int a, int b) throws DivisorIsZeroException//throws+类
aa.div(6, 0);//48行
{
}catch(Exception e)
{ // try
e.printStackTrace();
// {
}
} // if (0 == b)
} // throw new DivisorIsZeroException("除数不能为零!");
result:hello.Exception:
// } chu shu bu neng wei ling
at hello.exa.div(throwa.java:29)
// catch (DivisorIsZeroException e)
at hello.throwa.main(throwa.java:48)
// {
// e.printStackTrace();
class exa // }
{
int div(int a, int b)
{ if (0 == b)
int sum = 0; throw new DivisorIsZeroException("除数不能为零!");//throw new +对象
try int m = a / b;
{ return m;
if(0 }== b)
{
} throw new Exception("chu shu bu neng wei ling");
}
}catch(Exception
public classe)
TestA
{ {
e.printStackTrace();
} public static void main(String[] args)
sum = a/b; {
A aa = new A();
return sum;
} //aa.divide(6, 2);
} }
}
public class throwa
{ +++++++++++++++++++++++++++++++++++++++++++++++
public static void main(String[] args)
{
exa aa = new exa();
aa.div(6, 0);
}
}
class A
{
public void f()
{
System.out.println("AAAA");
}
}
// /*
// * 下面两行代码验证了:
// 编译器在编译时检测不出空指针异常错误,它只会在运行时抛出
// java.lang.NullPointerException异常
// */
// A aa2 = null;
// aa2.f(); //编译器编译时检测不会出错,只会在运行时抛出 java.lang.NullPointerException异常
}
}
异常的注意问题:
所有catch只有一个被执行
有可能所有的catch都没有执行
先catch子类异常再catch父类异常(若先catch父类,再子类,会报错)
catch与catch之间不能有其他代码
异常的范围
重写方法抛出的范围不能大于被重写方法排除的异常范围。
——————————————————————————————— 57
/*
2016年3月9日10:16:40
子类覆盖了基类方法时,
子类方法抛出异常的范围不能大于基类方法抛出的异常范围
子类方法可以不抛出异常,也可以只抛出基类方法的部分异常
但不可以抛出基类方法以外的异常
*/
//自定义异常A、B、C
class A extends Exception
{}
class B extends Exception
{}
class C extends Exception
{}
class M
{
void f() throws A, B
{ }
}
class N extends M
{
void f() throws A,B //可以throws A或B,也可以throws A,B 也可以不throws
或者throws C 即"子类覆盖了基类方法时,子类方法抛出异常的范围不能大于基类方
法抛出的异常范围"
{ }
}
class Test
{
public void k(M mm)
{
try
{
mm.f();
}
catch (A aa)
{}
catch (B bb)
{}
}
}
class TestExtendExce
{
public static void main(String[] args)
{
M m = new M();
N n = new N();
//System.out.println("1111");
}
}
//结果: 1111
+++++++++++++++++++++++++++++++++++++++++++++++++++++
异常的优缺点:
优点:强制程序员考虑程序的安全性和健壮性,增强了程序员对程序的可控性,有利于
代码的调试,把错误处理代码从常规代码给分离出来。
缺点:并不一定能够使程序的逻辑更清晰,并不能解决所有的问题。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
你学的任何知识要能够用自己的语言说出来。
+++++++++++++++++++++++++++++++++++++++++++++++++++
ToString()方法介绍
所有的类都默认自动继承了Object类
Object类中的toString方法返回的是类的名字和该对象哈希码组成的一个字符串
System.out.println(类对象名)
;
实际输出的是该对象的toString()方法所返回的字符串 toString()可用来打印对象
的信息。
为了实际需要,建议子类重写父类Object继承的toString方法。
————————————————
class Dian extends Object
{
public int x, y;
this.x = x;
this.y = y;
}
+++++++++++++++++++++++++++++++++++++ 2016年3月9日12:58:48 60
+++++++++++++++++++++++++++++++++++++++++++++++++
String类
在java中双引号括起来的字符串也被当作String对象
System.out.println("abc".length());//输出3
System.out.println("abc".equals("abc"));//输出ture
————————————————————————
——————————————————————
public class TestString_1{
//str = i;//error
//i = str;//error
str = String.valueOf(i);//valueOf中的o要大写。
System.out.println(str);
i = Integer.parseInt(str);
System.out.printf("i = %d\n", i);
}
} 运行结果:
123
++++++++++++++++++++++++++++++++++++++++++++++++++++
i = 123
printf和println的区别:
String和StringBuffer 结果:1的值+2的值 是 3;
1的值+2的值 是3;
String类对象一旦创建就不可更改 只读 println黄色的+号是连接符,不会显示
若经常对字符串内容进行修改,则使用StringBuffer。因其里面有很多修改方法
StringBuffer类的构造函数
String为final内容
不能改变为只读 public StringBuffer()创建一个空的没有任何字符的StringBuffer对象
StringBuffer内容
是可更改的 ————————————————————————————
public class TestStringBuffer{
public static void main(String[] args){
StringBuffer sb = new StringBuffer();
sb.append("abc");
append追加
sb.append("123");
System.out.println("sb = " + sb); //sb = abc123
sb.insert(3, "--");
System.out.println("sb = " + sb); //sb = abc--123
sb.delete(2,6); //把下标从2开始到6-1结束的字符删除
System.out.println("sb = " + sb); //sb = ab23
sb.reverse();
System.out.println("sb = " + sb); //sb = 32ba
String str = sb.toString();
System.out.printf("str = " + str); //str = 32ba
}
}
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
public StringBuffer(int capacity)创建一个不带字符,但具有制定初始容量
的字符串缓冲区。
public StringBuffer(String str)创建一个StringBuffer对象,包含与str对象
相同的字符序列。
——————————————————————————————
public class TestStringBuffer_2{
public static void main(String[] args){
StringBuffer sb = new StringBuffer("zhangsan");
//StringBuffer sb2 = "nzhangsan";//error
System.out.println(sb);
}
运行结果:zhangsan
}
++++++++++++++++++++++++++++++++++++++++++++ 2016年3月10日15:02:17 68
——————————————————————— 2016年3月10日15:30:43 69
数组
为什么需要数组:解决大量同类型数据的存储和使用问题,模拟显示世界。
一维数组
——————————————————————
public class TestArray_1
{
public static void main(String[] args)
{
//方式一
int[] arr1; 方法一运行结果:
arr1 = new int[3]; 0
1
arr1[0] = 0; 2
arr1[1] = 1; ************************
arr1[2] = 2;
showArr(arr1);
System.out.println("************************");
//方式二
int[] arr2 = new int[]{0,1,2};//常用形式
showArr(arr2);
System.out.println("************************");
// System.out.println(arr1); //error 一维数组的内容是不能通过
System.out.println()直接输出的,即便该数组的内容是引用且已经重写了toString方
法也不行
方法二运行结果:
// 0
// int[3] arr3 = new int[]{0,1,2}; // error 1
// int[] arr4 = new int[3]{0,1,2}; //error 2
// int[3] arr5 = new int[3]{0,1,2}; //error
************************
//
//方式三
int[] arr6 = {0,1,2}; //25行
showArr(arr6);
System.out.println("************************");
arr6 = new int[]{5,4,3,2,1}; //arr6本来是指向25行的{1,2,3}, 但是也
可以改变arr6的值,使其指向{5,4,3,2,1} 方法三运行结果: 0
showArr(arr6); 1
2
************************
5
4
3
2
1
}
创建并使用基本类型数组
创建并使用引用类型数组
多维数组
数组的拷贝
————————————————————————————
class TestArrayCopy {
public static void main(String[] args) {
int[] a = {1, 2, 3, 4, 5};
int[] b = {-1,-2,-3,-4,-5};
System.out.println("a = ");
for (int i=0; i<a.length; ++i){
System.out.println(a[i]); 运行结果:
a =
} 1
-1
System.out.println("b = "); -2
4
for (int i=0; i<b.length; ++i){ 5
System.out.println(b[i]); b =
} -1
1
-1
System.out.println("Hello World!"); -4
} -5
} Hello World!
//将arr1所指向的数组中下标从pos1开始的总共length个元素覆盖掉arr2所指向的数
组中从pos2开始的length个元素
+++++++++++++++++++++++++++++++++++++++++++++++++++++
数组的排序 Arrays
——————————————————————
import java.util.*;
Arrays.sort(data);//排序
System.out.println("排序后数组data中的内容是:");
showArray(data);
}
单道程序设计环境:计算机中除了操作系统之外,只存在一个用户程序,即用户
程序独占整个计算机资源。特点:资源的独占性,执行的顺序性,结果的再
现性。
多道程序设计环境:计算机中除了操作系统之外,存在多个用户程序,这些程序
同时运行。特点:间断性,失去封闭性,不可再现性。
进程的由来:为了不破坏“程序”这个词原有的含义,而又能刻画多个程序共同
运行是呈现出的新特征,所以引入了进程的概念。
进程:是一个动态的实体,是程序在某个数据集上的执行。它有自己的生命体,
它因创建而产生,因调度而运行,因等待资源或事件而被处于等待状态,因
完成任务而被撤销
线程 定义:是一个程序的不同执行路径。
多线程就是在单个程序内部在同一时刻进行多种运算
创建线程方法一:
创建:1、创建一个继承Thread的类(假定类名为A)
,并重写Thread中的run方法。
2、构建一个A类对象,假定对象名为aa。3、调用aa的start方法。
1、 定义一个实现Runnable接口的类, 假定为A; 2、 创建A类对象aa, 代码如下 A aa = new A();3、 利用
创建线程方法二: aa构造一个Thread对象tt, Thread tt = new Thread(aa);4、 调用tt中的start方法tt.start()启动线程;会
自动调用run方法
class A implements Runnable。此时仅仅是类A实现了Runnable接口,并不像方法一一样继承了Thread类,就可以使用Thread类的start()
方法。用实现了Runnable接口的类A去创造一个对象aa即A aa = new A()(创造了实现了Runnable的对象aa)。再使用Thread的构造方法
Thread(Runnable target)去构造一个Thread类的对象tt即Thread tt = new Thread(aa),其中Thread(aa)会自动调用aa中的Runnable。
然后Thread类的对象tt就可以调用Thread的start()方法启动线程,会自动调用run方法;
推荐使用Runnable来实现线程,因为定义一个实现Runnable接口的类A,A aa = new A();创建A类对
象aa,则通过一个aa对象可以构造多个Thread类的对象,Thread ta = new Thread(aa); Thread tb
= new Thread(aa);则引用变量ta和tb即线程ta和tb都指向通过aa创建的对象,对象aa在堆中分配的
是同一块内存,则在synchronized同步时,就不要用static来修饰类A内属性和对象了。
post(Runnable),最终还是在主线程中执行呢?...带着这些疑问,我们来开始
一、首先通过例子实现这两种方式。
1、继承 Thread 类。
时覆写了本类中的 run()方法就可以实现多线程操作了。
开启了三个线程。
PS:如果你也是使用 Android Studio,控制台中文输出可能是乱码,那么可
start()方法,
[java] view plain copy
可以看到,启动了三个不同的线程。
小结:通过上面的两个小例子程序,我们可以得知,只是实现 Runnable 接口,
并不能启动或者说实现一个线程。Runnable 接口,并不能代表一个线程。
UI, Handler.post()方法的源码如下,
[java] view plain copy
2.执行 Looper.loop()方法,该方法将会从消息循环中循环取出消息,取出消息
后,会执行下面的代码,
[java] view plain copy
通过上面的分析,这一块是不是更加清晰、明白了 !
[java] view plain copy
1. message.callback.run();
多线程的优势:编程简单,效率高,适合开发服务程序。
注意问题:
thread中的start()方法就是创建一个新的线程,并自动调用run()方法.
直接调用run()方法是不会创建一个新的线程的。
执行一个线程实际就是执行该线程run方法中的代码
执行完aa.start();后并不表示aa所对应的线程就一定会立即得到了执
行,aa.start();执行完后后只是表示aa线程具有了可以立即被CPU执行的
资格,但由于想抢占CPU执行的线程很多,CPU并不一定会立即去执行aa所
对应的线程。
一个Thread对象能且只能代表一个线程,一个Thread对象不能调用两次
start()方法,否则会抛出异常。
————————————————————— 创建线程方法一
class A extends Thread{
public void run(){
while (true){
System.out.println("AAAA");
}
}
}
class B{}
常用方法:
——————————————————————
class A extends Thread{
public void run()
{
System.out.println("AAAA");
System.out.printf("%s在执行!\n",Thread.currentThread().getName());
}
}
//System.out.println("BBBB");
System.out.printf("%s在执行!\n", Thread.currentThread().getName());
}
}
++++++++++++++++++++++++++++++++++++++++++++++++++++
控制:优先级控制,线程的休眠与让步,挂起和恢复,线程的串行化,生命周期
线程的优先级:java提供了一个线程调度器来监控程序中启动后进入就绪状态的
所有线程。线程的优先级用数字表示,从1到10,一个线程的缺省优先级是5
——————————————————————
public class TestPriority {
public static void main(String[] args)
{
Thread t1 = new Thread(new T1());
Thread t2 = new Thread(new T2());
//t1.setPriority(Thread.NORM_PRIORITY + 3); //考虑把本语句注释掉后
会怎样
t1.start();
t2.start();
}
}
无论是继承Thread类的run方法还是实现Runnable接口的run方法,都不能抛
出任何异常
——————————————————————— 2016年3月11日09:18:48 74
public class TestSleep_3{
public static void main(String[] args){
A aa = new A();
Thread tt = new Thread(aa);
tt.start();
子类抛出的异常范围不能超过父类,
} 父类的run方法根本没有抛出异常,
} 子类也当然不能抛出异常。
线程的让步:
————————————————————
public class TestYield
{
public static void main(String[] args)
{
MyThread mt = new MyThread();
Thread t1 = new Thread(mt);
Thread t2 = new Thread(mt);
t1.setName("线程A");
t2.setName("线程B");
t1.start();
t2.start();
}
}
class MyThread implements Runnable
{
public void run()
{
for(int i=1;i<=20;i++)
{
System.out.println(Thread.currentThread().getName()+": "+i);
if(0 == i%10)
{
Thread.yield();
}
}
}
}
++++++++++++++++++++++++++++++++++++++++++++++++++++
显示Eclipse中Console的
全部内容: 线程的串行化 TestJoin
preference->run/debug->
console设置limit
console output 复选框勾 生命周期控制 TestShutThread
掉方便调试时,查看全部
console。
线程的同步
———买票————————————————————————————
class A implements Runnable{
publicprivate
staticint
inttickets = 100;
tickets = 100;
public void run(){
买票程序的运行结果如下
图:这俩线程访问同一块 while(true){
资源,线程不断切换,导
致卖票重复,线程在执行 if(tickets > 0){
到哪句代码切换,由系统
决定。有可能某一线程在 System.out.printf("%s线程正在卖出第%d张票\n",
--tickets这句话刚要执 Thread.currentThread().getName(),tickets);
行时,票没减一,线程切
换了,那么另外一个线程 --tickets;
会重复卖票。
}
else{
break;
}
}
}
}
Synchronized关键字 可以用来修饰一个方法,或者一个方法内部的代码块。
格式:
Synchronized(类对象名aa)
{ 类似于数电状态机
同步代码块//3行
}
static
synchronized(类对象名aa) 结果就是:一个程序正在操作某资源的时候,将不允许其他线程操作该资源,即
一次只允许一个线程处理该资源。
Synchronized修饰一个方法时,实际霸占的是该方法的this指针所指向的对象,
即霸占的是正在调用该方法的对象。注:霸占的专业术语叫锁定,霸占住的
那个对象专业术语叫做监听器。
static静态属性和方法属于类本身,非静态属性和方法属于对象,只有在对象创建时
才会分配内存。此处用了static说明tickets和str是属于类本身,并不是在创建对象
时才创建。str是为了让那么多线程只锁定一个str。若是str不是static的,则str属
于对象不属于类本身,在对象创建时才创建,若是创建对象aa1和aa2,则会创建两个
—————————————————— str。就不能实现互斥访问同一资源(同一资源即str)。同理tckets若不是static
的,则创建对象时aa1和aa2会各有一个tickets即各有100张票,就不是同一资源
class A implements Runnable{ tickets,就不能实现互斥访问同一个tickets即仅仅只有100张票,而是各有100张票
private static int tickets = 100;//static不能省
static String str = new String("AA");//让各个线程锁定一个str。其static也不能省
thread中的start()方法
就是创建一个新的线程, 上面一句改为static String str = "AA";更好
并自动调用run()方法,
哪个线程start(),哪 public synchronized void run()//若把synchronized放在 void 前则会造成只
个线程就会锁定run方 //有一个线程运行
法。导致只能有一个线程 这两个static都不能省,因为如果省略任
运行。其他线程无法开启 { 意一个就会导致不是同一资源,如省略
tickets的static会导致各有100张票,则
while(true){ 会各卖100张票。省略str的static会导致
// synchronized(str)//线程霸占 某些票被卖多次,因为还没执行票减一的
时候,线程就切换了,则下一个线程又会
// { 接着卖此票,导致票卖多次。
if(tickets > 0){
System.out.printf("%s线程正在卖出第%d张票\n",
Thread.currentThread().getName(),tickets);
--tickets; 因为类的静态属性和方法属于类本身,非静态
属性和方法属于类的对象,只有对象被创建时
} 才会分配内存。假如类的属性是静态的,那么
你通过此类创建十个对象,这十个对象的静态
属性是共用一个属性,只有这一个属性,不是
十个属性。如果类的属性是非静态的,那么通
过此类创建十个对象,就会有十个属性。每个
对象都各有自己的属性。
else{
break;
}
// }
}
}
}
while (true){
synchronized (str) {
if (tickets > 0){
System.out.printf("%s线程正在卖出第%d张票\n",
Thread.currentThread().getName(), tickets);
--tickets;
}
else{
break;
}
}
} 不同线程使用run方法时的string_a是同一个,因为string
string_a = "synchronized_test"是放在同一个数据区存放,如
} 果是String string_a = new String("synchronized_test")就
不行因为new是在堆中分配,是不一样的。
}
推荐使用Runnable来实现线程,因为定义一个实现Runnable接口的类
A,A aa = new A();创建A类对象aa,则通过一个aa对象可以构造多个
Thread类的对象,Thread ta = new Thread(aa); Thread tb = new
Thread(aa);则Thread类的引用变量ta和tb即线程ta和tb都指向通过aa
创建的Thread类对象,对象aa在堆中分配的是同一块内存,则在
synchronized同步时,就不要用static来修饰类A内属性和对象了。
————2016年3月11日12:26:31 一本好书,能用自己的话说出来,通俗易懂。
——-——2016年3月11日14:21:09 80 “生产消费”
同步概念:通常,一些同时运行的线程需要共享数据。
notify和wait方法
this.notify()
;
功能:不是叫醒正在执行this.notify()的当前线程,而是叫醒其他线程。
如果当前时刻有其他线程因为执行了aa.wait()而陷入阻塞状态,则叫醒其
中的一个,所谓叫醒就是令某个线程因为wait而陷入阻塞的状态转入就绪状
态。
aa.wait();将执行aa.wait()的当前线程转入阻塞状态,让出cpu的控制权。并释
放对aa的锁定。
aa.notifyAll():叫醒其他所有因为aa.wait()而陷入阻塞状态的线程。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
awt
——————————————
import java.awt.*;
SynStack
同步栈
正常情况下index++被执行index=3,但index++没
被执行,线程就切换了,index仍然为2
index - - 语句被执行,index由2变为1即
index=1
/*
2009 年 6 月 24 日 15:24:35
生产和消费
*/
class SynStack
{
private char[] data = new char[6];
private int cnt = 0; //表示数组有效元素的个数
若把synchronized放
在 void 前则会造成
只有一个线程运行,则
就是ta生产线程或tb
消费线程只有一个在
运行,线程在执行
push或pop方法时,因
为synchronized则线
程互斥,线程不会进
行切换。
若把synchronized放在void前则会造成只有一个线程运行
一个对象只声明不赋值,则只会在内存的栈中创建
引用,堆中并无此引用的指向。
而null对象在堆中会被java的垃圾回收机制回收。
java中对象引用放在栈中,对象的实例放于堆中,
如果为null,说明只在栈中。
声明了一个对象的引用,jvm并没有开辟内存放入
一个对象。
互斥访问同一资源即对象sya
result:
GUI:图形化用户界面(了解一下就好。swing html才是专门的)
组件component:是图形用户界面的基本组成元素。凡是能够以图形化方式显示在
屏幕上并能够与用户进行交互的对象均为组件,如菜单,标签,文本框等。
分类:java.awt.Component
java.awt.MenuComponent
容器:组件通常不能独立地显示出来,必须将组件放在一定的容器中才可以显示
出来。而有一类特殊的组件是专门用来包含其他组件的,这类组件就叫作容
器。java.awt.Container是所有容器的父类,java.awt.Container继承自
java.awt.Component。容器类对象本身也是一个组件,具有组件的所有性质,
但反过来组件却不一定是组件。
Frame常用方法:
——————————————————————————
import java.awt.*;
panel
是容纳其他组件的组件。是容器。不能单独存在,必须得被添加到其他容器中。
————————————————
import java.awt.*;
布局管理器:容器对其中所包含组件的排列方式,包括组件的位置和大小设定,被称为
容器的布局(Layout)
。
GUI默认布局管理器:
————————————————————————————
import java.awt.*;
public class TestBorderLayout
{
public static void main(String args[])
{
Frame f;
f = new Frame("Border Layout");
Button bn = new Button("BN");
Button bs = new Button("BS");
Button bw = new Button("BW");
Button be = new Button("BE");
Button bc = new Button("BC");
f.add(bn, "North");
f.add(bs, "South");
f.add(bw, "West");
f.add(be, "East");
f.add(bc, "Center");
// 也可使用下述语句
/*
f.add(bn, BorderLayout.NORTH);
f.add(bs, BorderLayout.SOUTH);
f.add(bw, BorderLayout.WEST);
f.add(be, BorderLayout.EAST);
f.add(bc, BorderLayout.CENTER);
*/
f.setSize(200,200);
f.setVisible(true);
}
}
+++++++++++++++++++++++++++++++++++++++++++++++++++++
FlowLayout panel类默认布局管理器
————————————————————————————————
import java.awt.*;
GridLayout 将空间划分成规则的矩形网络。每个单元格区域大小相等。
————————————————————————
/*
2008年10月18日16:27:16
GridLayout的构造函数
public GriLayout(int, int);
的用法
*/
import java.awt.*;
public class TestGridLayout
{
public static void main(String args[])
{
Frame f = new Frame("GridLayout Example");
事件处理:
事件Event:用户对组件的一个操作,称之为一个事件。
事件源EventSourse:能够产生事件的GUI组件对象,如按钮、文本框等。
事件处理方法EventHandler:能够接收、解析和处理事件类对象,实现与用户交
互 功能的方法。
事件监听器EventListener:可以处理事件的一个类。
事件处理步骤:
假设事件为XXXX
1、向事件源注册某种事件监听器对象 addXXXXListener(……)
;
2、设计好可以处理这种事件的事件监听器
事件处理相关概念:
默认情况下事件源不会自动自动产生任何事物,程序员需要做两件事:1、告诉事
件源可以自动产生哪类事件,设计好可以处理这种事件的事件监听器。
一旦完成这两步操作,当用户对事件源进行操作时,事件源就会自动产生事件,
事件源就会自动把产生的时间封装成一个事件对象,事件源就会自动把封装好的事件对
象传递给事件监听器。时间监听器收到事件源发送过来的事件时,事件监听器就会自动
调用相应的事件处理方法来对该事件进行相应的处理。
java.awt.event包中含有所有的事件,常用的事件有:
ActionEvent:激活组件时发生的事件;
KeyEvent操作键盘时发生
MouseEvent操作鼠标时发生
WindowEvent:操作窗口时发生的事件,如最大化或最小化某一窗口。
————————————————————————
import java.awt.*;
import java.awt.event.*;
bn.addActionListener(aa);//aa监听bn,来对用户的单击操作进行处理
f.pack();
f.setVisible(true);
}
}
class A implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
System.out.println("perfect");
//System.exit(-1);//单击终止程序
}
}
+++++++++++++++++++++++++++++++++++++++++++
TestFiled监听器:
将整数转化为string的方法 toString
——————————————————————
public class TestInt
{
public static void main(String[] args)
{
int i = 345;
String str;
//第一种方法
// str = i + "";
// System.out.println("str = " + str);
// //第二种
// Integer it = new Integer(i);
// str = it.toString();
// System.out.println("str = " + str);
//第三种
// str = Integer.toString(i);
// System.out.println("str = " + str);
// //第四种:
// str = String.valueOf(i);
// System.out.println("str = " + str);
//第五种: 本方法不对
// str = i; //error 不兼容
// System.out.println("str = " + str);
}
}
+++++++++++++++++++++++++++++++++++++++++++++
三个文本框的相加运算(没听懂)88,89
————————————————
import java.awt.*;
import java.awt.event.*;
class TF
{
public static TextField tf1, tf2, tf3;
f.add(tf1);
f.add(Lb);
f.add(tf2);
f.add(bn);
f.add(tf3);
f.pack();
f.setVisible(true);
}
}
@Override
public void actionPerformed(ActionEvent e)//方法的首字母小写,以后的每
个单词首字母大写
{
//int num1 = Integer.parseInt( TestCaculator.tf1.getText() );
TestCaculator_1.tf3.setText(num3+"");
}
@Override
public void windowClosing(WindowEvent e)//是WindowEvent不是ActionEvent
{
System.exit(-1);
}
}
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
利用内部类。
import java.awt.*;
import java.awt.event.*;
class TF
{
private TextField tf1, tf2, tf3;
f.add(tf1);
f.add(Lb);
f.add(tf2);
f.add(bn);
f.add(tf3);
bn.addActionListener(new MyMonitor());
f.pack();
f.setVisible(true);
}
class MyMonitor implements ActionListener //内部类直接访问外部类成员
{
@Override
public void actionPerformed(ActionEvent e)
{
int num1 = Integer.parseInt( tf1.getText() );
int num2 = Integer.parseInt( tf2.getText() );
int num3 = num1 + num2;
tf3.setText(num3+"");
}
}
}
//升级版:TestCalculator.java
++++++++++++++++++++++++++++++++++++++++++
内部类
定义:在A类的内部但是所有方法的外部定义了一个B类,则B类就是A类的内部类,
A是B的外部类。
访问原则:内部类的方法可以访问外部类的所有成员。外部类的方法不可以直接
访问内部类的成员。TestInnerClass_1.java
内部类之间可以相互访问,只要在类中定义一个对象便可。
优点:可以让一个类方便的访问另一个类中的所有成员,增加程序的安全性,有
效的避免其它不想关类对该类的访问。
匿名类:
定义:是一种特殊的内部类
可以访问外部类的所有成员。
创建方式:1、继承父类
2、实现接口
3、实现抽象类
————————————————————————
import java.awt.*;
import java.awt.event.*;
f.addWindowListener( //11行
new WindowAdapter()//对象new完可以加花括号,再加方法//不规范
的
{
@Override
public void windowClosing(WindowEvent e)
{
f.setVisible(false);
System.exit(-1);
}
}
); //19行
f.setVisible(true);
}
}
可运行jar包的生成。
流就是数据传输的管道
———————--------—2016年3月12日19:39:48
新建一个流引用变量就是建立一 2016年3月13日09:59:04 95
个管道,让程序和设备之间连接
起来用于数据传输的管道。
也可以说是数据传输的线缆,如
海底光缆,区分处理流和节点流
流的分类
流的定义
定义:当前设备与其他设备用于数据传输的管道。流一定是类,但类不一定是流
byte 8bit 处理文本
原始流的功能弱,所以需要包裹
流,但是包裹流是在原始流的基
础上建立的,数据传输能力更强
Filewriter关闭close之前要flush一次性写到硬盘中。
是处理流,又叫包裹流
BufferedInputStream是处理流,又叫包裹流
FileInputStream是原始流,包裹流需要原始
流做基底,看JDK API1.6参考手册
包裹流的基底是原始流,字节包裹流基底是字节
原始流,字符包裹流的基底是字符原始流。
同理BufferedReader和BufferedWriter
应该定义一个临时的char类型的数组
字节流byte
字符流char
是处理流,又叫包裹流
将一个长整型数据写入字节数组,然后再从字节数组读出来。本质就是包裹流必须要有一个原始
流才能使用包裹流,先创造一个字节数组的原始流,再使用数据字节流包裹住字节数组的原始流
ByteArrayOutputStream流中toByteArray()方法的含义,摘自API“创建一个新分配的 byte 数
组。其大小是此输出流的当前大小,并且缓冲区的有效内容已复制到该数组中”
是处理流,又叫包裹流
是处理流,又叫包裹流
将System系统默认输出到显示器改为输
出的txt文件中,可以查卡错误日志。
InputStream流中常用的方法:
(语句针对的是byte)
Reader流的常用方法(与InputStream比没有public,语句针对的是char)
OutputStream流中常用的方法:
文件流:
字符流:FileReader FileWriter
FileInputStream的使用:(FileOutputStream 同理)
InputStream是用来读取字节的,是个抽象类,我们通常使用的是该类的子类
FileInputSteam是InputStream的子类,利用FileInputStream可以将一个文件
的内容按字节为单位读取出来。
常用的构造函数:
FileReader的使用:
(FileWriter同理)
Reader是用来读取字符的,是个抽象类,常用的是该类的子类
FileReader是Reader的子类,利用FileReader可以将一个文件的内容以字符为单
位读取出来。
常用的构造函数
public FileReader(String fileName) throws FileNotFoundException
字节流和字符流的区别:
FileInputStream和FileOutputStream可以完成所有格式文件的赋值
FileRead和FileWriter只可以完成文本文件的赋值,无法完成其他格式的复制。
因为字节是不需要解码和编码的,将字节转化为字符才存在这种问题。字节流
可以从所有格式的设备中读写数据,但字符流只能从文本格式的设备中读写数据。
————————————————————————————————————
import java.io.*;
try
{
fi = new FileInputStream("F:/java/妹妹来看我.mp3");
fo = new FileOutputStream("F:/Output.txt");
int ch;
finally
{
try
{
if(null != fi)
{
fi.close();
fi = null;
}
if(null != fo)
{
fo.close();
fo = null;
}
}
catch (Exception e)
{
e.printStackTrace();
System.exit(-1);
}
}
System.out.println("Copy success!");
}
}
——————————————————————————
import java.io.*;
ch = fr.read();
while (-1 != ch)
{
++cnt;
System.out.printf("%c", (char)ch);
ch = fr.read();
}
System.out.printf("该文件字符的个数是:%d\n", cnt);
fr.close();
}
}
_________________________________________________
/*
2009年7月3日10:42:43
通过字符流完成文本文件的复制
*/
import java.io.*;
ch = fr.read();
while (-1 != ch)
{
fw.write(ch);
ch = fr.read();
}
fw.flush();//刷新。有时候不写无法输出。
fr.close();//关闭
fw.close();
}
}
+++++++++++++++++++++++++++++++++++++++++++++要把例子都掌握了。
字符流只能处理文本,不能处理非文本文件,字节流还能处理视频,音乐等,凡是用steam
结尾的都是字节流
——————————————————————
/*
通过字节流可以完成音频格式文件,图像文件的复制,
实际上我们通过字节流可以完成任意格式文件的复制
缺点:没有缓冲区, 处理速度慢
可以参考对比"TestInputStreamOutputStreamCopy_3.java"
*/
import java.io.*;
public class TestInputStreamOutputStreamCopy
{
public static void main(String[] args) throws Exception
{
FileInputStream fr = new FileInputStream("E:\\IBM 教 学
\\java\\lesson_io\\妹妹来看我.mp3");
ch = fr.read();
while (-1 != ch)
{
fw.write(ch);
ch = fr.read();
}
fw.flush();
fr.close();
fw.close();
}
}
——————————————————————
/*
2016年3月12日21:35:49
本程序证明了:
带缓冲区的字节流处理文件的速度要快于不带缓冲区的字节流处理文件的速
度
可以参考对比"TestInputStreamOutputStreamCopy.java"
*/
import java.io.*;
len = bis.read(buf);
while (-1 != len)
{
bos.write(buf, 0, len);
len = bis.read(buf);
}
bos.flush();
bos.close();
bis.close();
}
}
++++++++++++++++++++++++++++++++++++++++++
缓冲流就是带有缓冲区的输入输出流
可以显著的减少我们对IO访问的次数,保护我们的硬盘。
缓冲流本身就是处理流(也叫包裹流),缓冲流必须得依附于节点流(也叫原始
流)
。处理流是包裹在原始节点流上的流,相当于包括在管道上的管道。
带缓冲区的字节流处理文件的速度要快于不带缓冲区的字节流处理文件的速度。
常用的构造方法:
BufferedReader(Reader in)
BufferedReader(Reader in,int sz)//sz为缓冲区的大小
BufferedWriter(Writer out)
BufferedWriter(Writer out, int sz)
BufferedInputStream(InputStream in)
BufferedInputStream(InputStream in, int size)
BufferedOutputStream(OutputStream out)
BufferedOutputStream(OutputStream out, int size)
缓冲输入流支持其父类的mark和reset方法。
BufferedReader提供了readLine方法用于读取一行字符串(以\r或\n分割)
BufferedReader提供了newLine用于写入一个行分隔符。
对于输出的缓冲流,写出的数据会先在内存中缓存,使用flus方法使在内存中
的数 据立刻写出。
BufferedOutputStream,BufferedInputStream 依 附 于
OutputStream,InputStream
BufferedOutputStream允许一次向硬盘写入多个字节的数据。
BufferedInputStream允许一次向程序中读入多个字节的数据。
BufferedOutputStream流中有 public int write(byte[] b)方法用来把byte
数组 中的数据输出到当前流所关联到的设备中。
BufferedInputStream流中有 public int read(byte[] b)方法用来把从当前
流所 关联到的设备中存入一个byte数组。
可以定义一个临时的byte类型的数组,用来作为输入流和输出流的中转枢纽。
——————————————————————————————————
import java.io.*;
try
{
//new FileOutputStream将String型转换为OutputStream型
bos = new BufferedOutputStream(new FileOutputStream("F:/ 来 看
我.txt"));//bos 输出流有个默认的缓冲区,大小为32个字节
bis = new BufferedInputStream(new FileInputStream("F:/java/感恩父
母.flv"));//bis 输入流有个默认的缓冲区,大小为32个字节
System.out.println("文件复制成功!");
}
}
+++++++++++++++++++++++++++++++++++++++
BufferedReader和BufferWriter可以提高读写文本文件内容的速度。
BufferedReader是个常用的流,流中有个readLine是个非常有用的方法。
——————————————————————————————————
import java.io.*;
try
{
br = new BufferedReader(
new FileReader("F:\\java\\TestBufferedReaderWriterCopy.java")
);
bw = new BufferedWriter(
new FileWriter("F:\\Writer.txt")
);
String str = null;
包裹流
数据流:Data//没听懂
DataInputStream能够以一种与机器无关的方式,直接从底层字节输入流读取
java基本类型和string类型的数据。依附于InputStream
常用方法:
public DataInputStream(InputStream in)
public final boolean readBoolean()
public final byte/char/double/…… readByte/readChar/readDouble()
public final String readUTF()
DataOutputStream能够以一种与机器无关的方式,直接将jaca基本类型和
string类型数据写出到其他的字节输出流中。依附于OutputStream
常用方法:
public DataOutputStream(OutputStream in)
public final boolean writeBoolean()
public final byte/char/double/…… writeByte/readChar/readDouble()
public final String writeUTF()
将一个长整型数据写入字节数组然后再从字节数组读出来。
————————————————————————————
import java.io.*;
转换流:
OutputStreamWriter流是把OutputSteam流转换成Writer流
readLine()与回车符的问题
readLine()返回的是“”而不是null,“”表示空字符串,null表示空指针,空
指针就是空地址,空地址就是不指向任何存储单元的意思。
Print流:只有输出,没有输入。
分类:PrintWriter,PrintStream
标准输入输出的重定向
什么叫容器? 容器分为以下三类:
有一个类,这个类里面可以放置其他类的对象, set接口:无序无重复
并可以对存储的这些对象进行排序等操作。 list接口:有序有重复
这个类就叫容器。也可以叫做集合。 map接口:key-value映射对
collection接口 通过这三种接口可实现容器(类)
编程实现将键盘输入的数据输入A文件中,如果输入有误,则把出错信息输出到B
文件中。
e.printStackTrace();默认是把错误信息输出到System.err所关联的设备中
对象的序列化:ObjectOutputSteam,ObjectInputStream.
++++++++++++++++++++++++++++++++++2016年3月13日12:24:36 96 先预习再去看
视频
容器里面放着的是对象。 容器里面放的都是某类型的类new出来的对象,如"张三"
String类new出来的对象。66.66是Double类new出来的对象
————————————————————
import java.util.*;
class A{ Object类的toString方法返回的是类的名字和该对象哈
希码组成的一个字符串
public String toString(){ System.out.println(类对象名);实际输出的是该对象
return "哈哈"; 的toString()方法,由于其返回的是该对象哈希码组成
的一个字符串。为了实际需要, 建议子类重写父类
} Object继承的toString方法。
}
System.out.println(al.get(2)); 通过下标获取容器内的对象
//System.out.println(al);
}
运行结果:
} 66.66
66.66
++++++++++++++++++++++++++++++++++++++++++++
为什么需要容器:数组存在的缺陷:数组长度难以扩充,数据类型必须相同。
集合就是将若干用途、性质相同或相近的“数据”组合而成一个整体。
集合可分为:Set,List,Map
Collection接口方法介绍:
int size();
Collection接口的子接口
List接口:实现List接口的容器类中的元素是有顺序的,而且可以重复。list:有序有重复
Set接口:容器类中的元素是没有顺序的,不可重复。set:无序无重复
Map接口:
Collection类常用算法:
void reverse(List)对List容器内的对象进行逆序排列。
——————————————————
import java.util.*;
————————————————————————————
import java.util.*;
@Override
public String toString() 父类引用变量Object o指向调用compareTo()方
{ 法的子类对象,则此父类引用变量可以强制转
换为子类对象,(Student)o == new Student()
return id + " " + name; //1000张三
//System.out.println();
}
运行结果:
[1000 张三, 1001 李四, 1002 王五, 1003 小娟]
list:有序有重复
set接口 set:无序无重复
注意hashCode()方法的大小写
正确的运行结果:不能有重复
不重写equals()和hashCode()
方法的运行结果,有重复,不对
// public int hashCode()
// {
// return id * this.name.hashCode();
// }
只要以hash字符开头或结尾的类都要重写equals()和hashCode()方法。
public class TestSet
{
public static void main(String[] args)
{
Set S = new TreeSet(); //TreeSet
S.add(new Student(1000, "张三"));
S.add(new Student(1003, "小娟"));
S.add(new Student(1002, "王五"));
S.add(new Student(1001, "李四"));
S.add(new Student(1001, "李四"));
S.add(new Student(1001, "李四"));
S.add(new Student(1001, "李四"));
S.add(new Student(1001, "李四"));
S.add(new Student(1001, "李四"));
System.out.println(S); //[
}
}
为什么要重写hashCode()方法?
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*******equals和hashCode方法的使用
String和Integer这些Java自带的类都重写了hashCode方法,如果String和Integernew
出来的对象的内容是一样的,则这些对象的hashCode返回值也是一样的,虽然这些对
象占用的是不同的内存,不过用户自定义类型则不同,如本程序的A类,即便是两个内
容一模一样的A类对象,它们返回的hashCode值也是不一样的,但是两个内容一模一样
的Integer类对象或者String类对象返回的hashCode值却是一样的,因为系统自带的
String和Integer类都已经重写了Object的hashCode方法嘛!
如果程序员希望自己定义的类对象,占用不同内存空间但内容却是一样的对象调用
hashCode方法返回值是一样的,则程序员就必须自己重写hashCode方法,如本程序的B
类
如果程序员希望自己定义的类对象,占用不同内存空间但内容却是一样的对象调
用hashCode方法返回值是一样的,则程序员就必须自己重写hashCode方法,如本程序的
B类
——————————————————————————————————
class A
{
private int id;
class B
{
private int id;
@Override
public int hashCode()
{
return new Integer(id).hashCode(); 用return (this.id + this.name.hashCode());来取
} 代因为new一个对象占用内存
}
"haha".hashCode() = 3194802
"haha".hashCode() = 3194802
Iterator接口
boolean hasNext();是用来判断当前游标后面还是否存在元素,存在则返回真,否则为
假
Object next();先返回当前游标右边的元素,然后游标后移一个位置,相当于i++
——————————————————————————
import java.util.*;
class Point
{
private int i, j;
TreeSet类:
HashSet类:
Map接口 102
————————————————————————
import java.util.*;
class Student
{
private int id;
private String name;
private int age;
public Student()
{
}
//遍历所有的元素
System.out.println("hm容器中所有的元素是:");
Set s = hm.keySet(); //通过keySet方法获取到当前容器键的集合,实际就
是Integer对象的集合
Iterator it = s.iterator();//通过it指针就可以指向s容器里面的每一个关
键字
while (it.hasNext()){//it.hasNext()指针指向下一个
//int Key = (Integer)it.next(); // (Integer) 不能省, 利用了自
动拆分技术
Integer kk = (Integer)it.next();
System.out.println(hm.get(kk));
}
System.out.println("直接查找某一元素");
System.out.println( hm.get(1003) );
System.out.println( hm.get(1005) ); // 如 果 找 不 到 则 直 接 返 回
null,而不是抛出异常
}
}
++++++++++++++++++++++++++++++++++++++++++++++++++++++
感觉最可怕的就是外面瞬息万变,而我一成不变,还不知道外面怎么变。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
查看手册某些类或方法带有<>尖括号的才
能使用泛型
泛型:是用来限制传入容器、接口的数据类型。 容器里面保存的是某个类的对象
——————————————————————————
import java.util.*;
class Student
{
private int id;
private String name;
private int age;
public Student()
{
}
红色划线的部分
就是泛型,指定
传入容器的类型
//制定当前时刻传入的类型,就不要强制转换成子类型。
hm.put(1001, new Student(1001, "zhangsan", 20));
hm.put(1003, new Student(1003, "lisi", 30));
hm.put(1004, new Student(1004, "wangwu", 10));
hm.put(1002, new Student(1002, "baichi", 20));
//遍历所有的元素
System.out.println("hm容器中所有的元素是:");
Set<Integer> s = hm.keySet();
Iterator<Integer> it = s.iterator();
while (it.hasNext())
{
int Key = it.next(); // it.next() 前面不需要加(Integer) 不能省
//Integer itg = it.next(); //it.next() 前 面 不 需 要 加 (Integer)
59和60行等价
System.out.println(hm.get(Key));
}
System.out.println("直接查找某一元素");
System.out.println( hm.get(1003) );
System.out.println( hm.get(1005) ); //如果找不到 则直接返回null
运行结果:
} hm容器中所有的元素是:
1001 zhangsan 20
} 1002 baichi 20
1003 lisi 30
++++++++++++++++++++++++++++++++++++++++++++
1004 wangwu 10
直接查找某一元素
网络编程(不是重点) 与 jdc 差不多 1003 lisi 30
null
网络程序:能够接受另一台计算机发送过来的数据或向一台计算机发送数据的程
序
IP:能够在网络中唯一标示一台主机的编号就是IP,IP的地址是一个逻辑地址。32
位,4个字节,常用点分十进制的格式表示。
(从哪发到哪)
端口号:发送到机器的某个程序。
协议:为进行网络中的数据交换(通信)而建立的规则、标准或约定。
(怎么发)
TCP:面向连接的可靠的传输协议。类似于写信
UDP:是无连接的,不可靠的传输协议。类似于写信,发邮件
套接字(socket)
基于UDP的socket编程步骤:
1、定义码头:即定义一个DatagramSocket对象ds
2、定义可以用来接受或发送数据的集装箱:定义:DatagramPacket对象dp
3、在码头上用集装箱接受对方发送过来的数据:ds.receive(dp);
或者在码头上把集装箱中的数据发送给对方:ds.send(dp);
4、关闭码头:ds.close()
//定义可以用来接受数据的集装箱
byte buf[] = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf, buf.length);
try
{
while(true)
{
//在码头上用集装箱接受对方发送过来的数据
ds.receive(dp); //注意:本语句执行完毕就意味着,dp数据包中就
已经含有了从客户端接收过来的数据
//从集装箱中取出对方发送过来的数据
ByteArrayInputStream bais = new
ByteArrayInputStream(dp.getData()); //1、 ByteArrayInputStream的内核必须是个
字节数组,并且是从该字节数组中读取数据 2、dp.getData()表示把dp集装箱中的数
据转化为一个字节数组并返回该字节数组
DataInputStream dis = new DataInputStream(bais);
System.out.println(dis.readLong());
}
}
catch (Exception e)
{
e.printStackTrace();
ds.close(); //关闭码头
}
}
}
/*
在JDK 1.6中的运行结果是:
----------------------------------
10000
数据源自: 127.0.0.1 : 1464
10000
数据源自: 127.0.0.1 : 1471
10000
数据源自: 127.0.0.1 : 1474
----------------------------------
*/
———————————— TestUDPClient ————————
import java.net.*;
import java.io.*;
//13行到23行完成的功能是: 定义可以发送数据的集装箱dp
long n = 10000L; //13行
ByteArrayOutputStream baos = new ByteArrayOutputStream(); // 注 意
ByteArrayOutputStream 的 所 有 构 造 函 数 都 没 有 byte[] buf 这 样 的 形 参 , 即 定 义
ByteArrayOutputStream流对象时是不能指定byte数组的,因为这个连接到的byte数组
是 由 ByteArrayOutputStream 自 动 生 成 的 9 行 API:"public
ByteArrayOutputStream(): 创建一个新的 byte 数组输出流。缓冲区的容量最初是 32
字节,如有必要可增加其大小。 "
//9行代码一旦执行完毕,意味着两点: 1、在内
存中生成了一个大小为32个字节的byte数组 2、有一根叫做baos的管道已链接到了该
byte数组中,并且可以通过这个管道向该数组中写入数据
//虽然此时可以通过baos向baos所连接到的在
内存中分配好的byte数组中写入数据,但是ByteArrayOutputStream流并没有提供可以
直接把long类型数据直接写入ByteArrayOutputStream流所连接到的byte数组中的方法,
简单说我们没法通过baos向baos所连接到的byte数组中写入long类型的数据, 查API文
档可以发现: ByteArrayOutputStream流中并没有类似writeLong()这样的方法,但是
DataOutputStream流中却有writeLong() writeFloat()等方法
DataOutputStream dos = new DataOutputStream(baos);
dos.writeLong(n); //把n变量所代表的10000L写入dos所依附的baos管道所
连接到的内存中的大小为32字节的byte数组中
//在码头上把集装箱中的数据发送给对方
ds.send(dp);
//关闭码头
ds.close();
}
}
++++++++++++++++++++++++++ 看程序首先得知道它运行的结果。
数组数据→集装箱→码头
这样数据就发送出去了。