java是一门很好的语言,也是一门庞杂的系统,学习过程中要善于记录和积累。
javaSE(标准版) javaEE(企业版) javaME(微型版)
JDK(java开发工具包)JRE(java运行环境)IDE(集成开发环境)
- Java SE(Java Platform,Standard Edition)。Java SE 以前称为 J2SE。它允许开发和部署在桌面、服务器、嵌入式环境和实时环境中使用的 Java 应用程序。Java SE 包含了支持 Java Web 服务开发的类,并为 Java Platform,Enterprise Edition(Java EE)提供基础。 J2SE就是做那种桌面安装程序样的,像QQ,WORD那种应用程序。
- Java EE(Java Platform,Enterprise Edition)。这个版本以前称为 J2EE。企业版本帮助开发和部署可移植、健壮、可伸缩且安全的服务器端 Java 应用程序。Java EE 是在 Java SE 的基础上构建的,它提供 Web 服务、组件模型、管理和通信 API,可以用来实现企业级的面向服务体系结构(service-oriented architecture,SOA)和 Web 2.0 应用程序。 J2EE 就是做基于Internet的应用程序,像选课系统,企业网站,银行系统之类的。
- Java ME(Java Platform,Micro Edition)。这个版本以前称为 J2ME。Java ME 为在移动设备和嵌入式设备(比如手机、PDA、电视机顶盒和打印机)上运行的应用程序提供一个健壮且灵活的环境。Java ME 包括灵活的用户界面、健壮的安全模型、许多内置的网络协议以及对可以动态下载的连网和离线应用程序的丰富支持。基于 Java ME 规范的应用程序只需编写一次,就可以用于许多设备,而且可以利用每个设备的本机功能。 J2ME就是做嵌入式系统开发的,像手机游戏之类的,像现在流行的Android操作系统。
- JDK(Java Development Kit)。
- JRE(Java Runtime Environment)
- IDE(Ind Depvelopment Environment)
JDK、Eclipse
byte char boolean short int long float double
简单说明:byte 8个bit 因为是有符号的所以取值范围(-128~127) ;char和short 16个bit,char是无符号的取值范围(0~65535) ; int和float 都是32个bit ;long和double都是64个bit
byte和char的区别:1.Char是无符号型的,可以表示一个整数,不能表示负数;而byte是有符号型的,可以表示-128—127的数;2.char可以表中文字符,byte不可以;3.char、byte、int对于英文字符,可以相互转化
public class DataTypeTest {
public static void main (String[] args){
DataTypeTest dtt = new DataTypeTest();
dtt.testByte();
dtt.testChar();
dtt.testChange();
}
/**实验byte
* Char是无符号型的,可以表示一个整数,不能表示负数;
* 而byte是有符号型的,可以表示-128—127 的数
*/
public void testByte(){
byte b1 = 1;
byte b2 = -1;
byte b3 = -128;
byte b4 = 127;
char c = (char) -3;//char不能识别负数,强转一下编译器不会报错,但是仍无法识别
System.out.println(b1);//1
System.out.println(b2);//-1
System.out.println(b3);//-128
System.out.println(b4);//127
System.out.println(c);//?
System.out.println("------------------");
}
/**实验char
* char可以表示中文字符,byte不可以
* char类型在存储的时候就是整数,对应一张Unicode编码表
* 'A'对应65,而'a'对应97,所以char类型可以和int类型进行运算
*/
public void testChar(){
char c1 = '中', c2 = '国' , c3 = 1;
byte b1 = (byte)c1;//45
int i = '中'+1;//20014
System.out.println(c1);
System.out.println(c2);
System.out.println(c3);
System.out.println(b1);//问题:输出的数字的含义
System.out.println("i="+i);
System.out.println("------------------");
}
/**char、byte、int对于英文字符,可以相互转化
*
*/
public void testChange(){
byte b = 'b';//98
char c1 = (char)b;//b
char c2 = 'c';//c
int i = c2;//99
System.out.println(b);
System.out.println(c1);
System.out.println(c2);
System.out.println(i);
System.out.println("------------------");
}
}
基本数据类型 | 分类 | 大小 | 取值范围 | 默认初始值 |
---|---|---|---|---|
byte | 整型 | 1字节 8bit | 【-128 127】 | 0 |
int | 整型 | 4字节 32bit | 【-2*10^31 2*10^31-1 】 | 0 |
short | 整型 | 2字节 16bit | 【-2*10^15 2*10^15-1 】 | 0 |
long | 整型 | 8字节 64bit | 【-2*10^63 2*10^63-1 】 | |
char | 字符型 | 2字节 16bit | 【-2*10^31 2*10^31-1 】 | |
float | 浮点型 | 4字节 32bit | 【3.402823e+38 ~ 1.401298e-45】 | |
double | 浮点型 | 8字节 64bit | 【1.797693e+308~ 4.9000000e-324】 |
String 和 自定义类 接口 抽象类
String、StringBuffer和StringBuilder三者的区别:1.String是常量,StringBuffer和StringBuilder是变量,修改时不生成新的对象,内存使用上占优势;2.StringBuffer是线程安全的,StringBuilder非线程安全;3.执行速度:(StringBuilder,StringBuffer)>String;
综上所诉:1.当数据量不是很大的时候用String;2.单线程用StringBuilder;3.多线程用StringBuffer 三者区别详解
只有确保了命名的唯一性和描述性,才能保证资源之间不相互冲突并且便于理解记忆。
① 标识符的组成:字母,数字,下划线,$,不能以数字开头,不能使用关键字和保留关键字。ps:关键字是指java中已经定义的具有特定功能的标识符,不能用作普通标识符
② 包的命名
Java包的名字都是由小写单词组成。每一名Java程序员都可以编写属于自己的Java包,为了保障每个Java包命名的惟一性,最新的Java编程规范要求程序员在自己定义的包的名称之前加上惟一的前缀。由于互联网上的域名是不会重复的,所以程序员一般采用自己在互联网上的域名作为自己程序包的惟一前缀。
例如:net.frontfree.javagroup。
③ 类的命名
类的名字必须由大写字母开头,一个单词中的其他字母均为小写。如果类名称由多个单词组成,则建议将每个单词的首字母均用大写,例如TestPage。如果类名称中包含单词缩写,则建议将这个词的每个字母均用大写,如:XMLExample。由于类是设计用来代表对象的,所以建议在命名类时应尽量选择名词。
④ 方法的命名
方法的名字的第1个单词应以小写字母开头,后面的单词则建议用大写字母开头(驼峰原则)。
例如:sendMessge()。
⑤ 常量的命名
常量的名字应该都使用大写字母,并且指出该常量完整含义。如果一个常量名称由多个单词组成,则建议用下划线来分割这些单词。
例如:MAX_VALUE。
⑥ 参数的命名(驼峰原则)
参数的命名规范和方法的命名规范相同,而且为了避免阅读程序时造成迷惑,请在尽量保证在参数名称为一个单词的情况下,参数的命名尽可能明确。**注意:**1、类的属性允许不进行初始化;2、方法内部的变量要进行初始化
⑦ javaDoc注释
Javadoc注释是一种多行注释,以/*开头,而以/结束,注释可以包含一些HTML标记符和专门的关键词。使用Javadoc注释的好处是编写的注释可以被自动转化为在线文档,省去了单独编写程序文档的麻烦。例如:
/**
*This is an example of
* Javadoc
*
*@author darchon
*@version 0.1, 10/11/2002
*/
//单行注释
块注释
/*注释快*/
在每个程序的最开始部分,一般都用Javadoc注释进行程序的总体描述以及版权信息。在主程序中可以为每个类、接口、方法、变量添加Javadoc注释,每个注释的开头部分先用一句话概括该类、接口、方法、变量所完成的功能,这句话应单独占据一行以突出其概括作用,在这句话后面可以跟随更加详细的描述段落。
在描述性段落之后还可以跟随一些以Javadoc注释标签开头的特殊段落,例如上面例子中的@auther和@version,这些段落将在生成的文档中以特定方式显示。
虽然添加注释不会使一个设计低劣的程序变成好的程序,但是如果按照编程规范编写程序,并且为程序添加良好的注释,却可以帮助编写出设计优美、运行高效且易于理解的程序,尤其在多人合作完成同一项目时,编程规范非常重要。俗话说”磨刀不误砍柴工”,花费一点时间去适应一下Java编程规范是有好处的。
分支语句(条件语句)
循环语句()
成员变量:在类体的变量部分中定义的变量,也称为属性。
局部变量:是指在程序中,定义在特定的方法或语句块的变量,是相对与全局变量而言的。
成员遍历和局部变量的区别
public class Test{
int a=0; //全局变量
public static void main(String[] args){
int b =0;//局部变量
}
}
1.定义的位置不同:成员变量直接定义在类内部,局部变量是定义某个方法体内部;2.作用域不同:成员变量适用于整个类和与该类相关的类,局部变量只适用于该方法内部;3初始值不同:成员变量可以不显式初始化它们可以由系统设定默认值,局部变量没有默认值,所以必须设定初始赋值;4.不同方法可以有重名的局部变量;5.如果类变量和局部变量重名,局部变量更有优先级;
成员变量又可以细分为:实例变量、类变量(静态变量)
public class Clothes
{
String id; //实例变量
private String colorType; //实例变量
private int size; //实例变量
private static String depart; //类变量
final String design="yangzi"; //常量
}
实例变量和类变量的区别
1.实例变量:不用static修饰,它只能通过对象调用而且所有对象的同一个实例变量是共享不同的内存空间的;
2.类变量:又叫静态变量,用static修饰,它可以直接用类名调用也可以用对象调用,而且所有对象的同一个类变量都是共享同一块内存空间的;
1.程序运行的时候构造方法就被加载;2.每个类都有构造方法,如果程序员给类提供构造方法,编译器会自动创建一个默认的构造方法;
3.构造方法重载类似于方法的重载,一个类可以有多个构造方法,但参数列表必不同。
含义:“static”关键字表明一个成员变量或者是成员方法可以在没有所属的类的实例变量的情况下被访问。Java中static方法不能被覆盖, 因为方法覆盖是基于运行时动态绑定的,而static方法是编译时静态绑定的。static方法跟类的任何实例都不相关,所以概念上不适用。
是静态修饰符,什么叫静态修饰符呢?大家都知道,在程序中任何变量或者代码都是在编译时由系统自动分配内存来存储的,而所谓静态就是指在编译后所分配的内存会一直存在,直到程序退出内存才会释放这个空间,也就是只要程序在运行,那么这块内存就会一直存在。这样做有什么意义呢?
在Java程序里面,所有的东西都是对象,而对象的抽象就是类,对于一个类而言,如果要使用他的成员,那么普通情况下必须先实例化对象后,通过对象的引用才能够访问这些成员,但是有种情况例外,就是该成员是用static声明的(在这里所讲排除了类的访问控制)
静态变量和静态方法:
1.静态变量可以直接被类和对象调用;2.静态方法中不能直接调用非静态变量和非静态方法,可以通过创建对象调用;3.普通方法中可以直接调用 类中的静态和非静态变量;
实例:
public class HelloWorld {
static String s = "你好,静态变量!";// 静态变量
String s1 = "你好,我是非静态变量!";
public static void say() {
System.out.println("你好,我是静态方法,我被调用了");
// System.out.println(s1); 这句编译器会报错,因为静态方法中不能调用非静态变量
// 如果想在静态方法中调用非静态变量,可以创建类的对象,通过该对象调用非静态变量
HelloWorld hw = new HelloWorld();
System.out.println("我是通过在静态方法中实例化类,通过类调用静态变量:" + hw.s1);
// 静态方法中不能直接调用非静态方法,需要创建对象来调用
// shuo(); 编译器会报错
hw.shuo();
}
public void shuo() {
System.out.println("你好,我是普通方法,我被调用了");
System.out.println(s);
System.out.println(s1);
}
public static void main(String[] args) {
// 类直接调用静态变量
System.out.println(HelloWorld.s);
// 对象调用静态变量
HelloWorld hw = new HelloWorld();
System.out.println(hw.s);
// 类直接调用静态方法
HelloWorld.say();
// 对象调用静态方法
hw.say();
// shuo();静态方法中不能直接调用非静态方法
}
}
静态初始化块:
静态初始化块只在类加载时执行,且只会执行一次,同时静态初始化块只能给静态变量赋值,不能初始化普通的成员变量。
实例:
public class HelloWorld {
static int num1;
int num2;
int num3;
static {
num1 = 1;
System.out.println("通过静态初始化块赋值");
}
{
num2 = 2;
System.out.println("通过初始化块赋值");
}
public HelloWorld(){
num3 = 3;
System.out.println("通过构造方法赋值");
}
public static void main(String[] args) {
HelloWorld hw = new HelloWorld();//实例化类
System.out.println("num1:"+ num1);
System.out.println("num2:"+ hw.num2);
System.out.println("num3:"+ hw.num3);
HelloWorld hw2 = new HelloWorld();//再次实例化
}
}
实例总结:1.执行顺序上,先执行静态代码块,再执行普通代码块,最后执行构造方法。2.注意:静态代码块只在类加载时执行一次,所以在再次创建对象是静态初始化块并未再次执行。3.静态初始化块只能给静态变量赋值,不能初始化普通的成员变量;
参数按值传递,传递的是值的拷贝,也就是说传递后就互不相关了,不会影响原值。
参数按引用传递,传递的是值的引用,也就是说传递前和传递后都指向同一个引用(也就是同一个内存空间),因此,外部对引用对象所做的改变会反映到所有的对象上。
按值传递和引用传递详解
Object()
默认构造方法
clone()
创建并返回此对象的一个副本。
equals(Object obj)
指示某个其他对象是否与此对象“相等”。
finalize()
当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
getClass()
返回一个对象的运行时类。
hashCode()
返回该对象的哈希码值。
notify()
唤醒在此对象监视器上等待的单个线程。
notifyAll()
唤醒在此对象监视器上等待的所有线程。
toString()
返回该对象的字符串表示。
wait()
导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。
wait(long timeout)
导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量。
wait(long timeout, int nanos)
导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。
(10)UML
面向对象的编程优点:代码开发模块化,易于维护和理解,代码复用性,增强代码的可维护性和灵活性,
- 封装:将对象封装成类,类隐藏内部的实现细节,统一提供属性和方法,便于代码的维护。
java中的访问修饰符: 1.private:只有本类内部可以访问,且不能被访问(继承);2.默认(不加访问修饰符),只能在本类和同一包中使用 3.protected:能在本类,同一包(package)下,和该类的子类被访问(该子类可以不和父类在一个包下);4.public:公开的,都可以被访问(继承)内部类:??????
- 继承:继承是类与类之间的一种关系,子类可以使用父类的属性和方法(父类的属性和方法不能是privata),增加了代码的复用性,也为多态的实现提供了前提。
注意:1.java中只能实现单继承;2.super()代表在子类中调用父类的构造方法;3.this.属性/this.方法,表示访问本类中的属性和方法,this()代表调用本类的构造方法;3. 类与类之间的关系:继承关系;依赖关系(该类对象作为另 一个类中一个方法的参数)实现关系(实现是类与接口之间最常见的关系)类与类之间的关系详解4.final关键字:可以修饰类、方法、属性和变量,
修饰类该类不能被继承,修饰方法该方法不能被覆盖,修饰属性该属性不能自动初始化,修饰变量该变量只能赋一次值
5.java中继承的执行顺序:父类属性初始化–>父类构造方法–>子类属性初始化–>子类构造方法
class A {
static {
System.out.println("父类静态初始化块赋值");
}
{
System.out.println("父类初始化块赋值");
}
public A(){
System.out.println("父类构造方法赋值");
}
}
class B extends A{
static {
System.out.println("子类静态初始化块");
}
{
System.out.println("子类初始化块");
}
public B(){
System.out.println("子类构造方法");
}
}
public class Test {
public static void main(String[] args) {
B b1 = new B();//实例化类
System.out.println();
B b2 = new B();//再次实例化
}
}
执行结果:(即为顺序)
父类静态初始化块赋值
子类静态初始化块
父类初始化块赋值
父类构造方法赋值
子类初始化块
子类构造方法
父类初始化块赋值
父类构造方法赋值
子类初始化块
子类构造方法
多态:重用、重载、动态调用构成了多态。体现:子类生产父类对象
Animal A = new Cat();
class Father{
public void fun1(){
System.out.println("父类的fun1()");
}
public void fun2(){
System.out.println("父类的fun2()");
}
}
class Son extends Father{
public void fun1(){
System.out.println("子类的fun1()");
}
public void fun2(int i){
System.out.println("子类的fun2(int i)");
}
}
public class duotai {
public static void main(String[] args) {
Father f = new Father();
f.fun1();
f.fun2();
System.out.println();
Son s = new Son();
s.fun1();
s.fun2(1);
s.fun2();
System.out.println();
Father f1 = new Son();
f1.fun1();//父类的fun1()被重写/覆盖,所以调用的是子类的fun1()
f1.fun2();//父类中没有定义fun2(int i)所以不能被调用
}
}
以上实例说明:1.子类生成父类对象,子类重写/覆盖(返回值类型、方法名和参数都相同但方法的内部实现不同)父类的方法,调用时直接调用子类的方法;2.子类重载(返回值和方法名相同,参数不同)父类的方法,根据参数值调用子类方法;3.子类生产父类对象,调用的方法父类中必须要有相应的实现,在子类中被重写。
关于多态的一个经典实例:
class A {
public String show(D obj){
return ("A and D");
}
public String show(A obj){
return ("A and A");
}
}
class B extends A{
public String show(B obj){
return ("B and B");
}
public String show(A obj){
return ("B and A");
}
}
class C extends B{}
class D extends B{}
public class jingdianduotai {
public static void main(String[] args) {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println(a1.show(d));//A and D
System.out.println(a1.show(b));//A and A
System.out.println(a1.show(c));//A and A
System.out.println();
System.out.println(a2.show(d));//A and D
System.out.println(a2.show(a1));//B and A,子类重写了父类的方法
System.out.println(a2.show(b));//B and A
System.out.println(a2.show(c));//B and A
System.out.println();
System.out.println(b.show(b));//B and B
/*
* 1.先在类B中招找方法show(c)
* 2.没有
* 3.再找b.show(super(c))即b.show(b)
* 4.所以为B and B
*/
System.out.println(b.show(c));
System.out.println(b.show(d));//A and D,子类继承了父类的方法
}
}
引用类型转换:1.向上类型转换(隐式/自动类型转换),小类型到大类型转换(无风险)Animal animal = new Dog();;2.向下类型转换(强制类型转换),大类型到小 类型(存在方向)Animal animal = new Dog();Dog dog = (Dog)animal;与Dog dog = new (Dog)Animal();不同,后者不能进行类型转换。用 instanceof关键字验证(animal instanceof Cat)是否能进行类型装换。
class Dog extends Animal{
public void eat(){
System.out.println("狗吃骨头");
}
public Dog(){
System.out.println("Dog执行了!!");
}
}
class Cat extends Animal{
public void eat(){
System.out.println("猫吃鱼");
}
public Cat(){
System.out.println("Cat执行了!!");
}
}
public class TestInstanceOf {
public static void main(String[] args) {
Animal animal = new Dog();
if(animal instanceof Dog){
Dog dogn = (Dog)animal;
}else{
System.out.println("Dog-->animal无法进行类型转换!");
}
if(animal instanceof Cat){
Cat cat = (Cat)animal;
}else{
System.out.println("Cat-->animal无法进行类型转换!");
}
}
}
多态总结: 方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写(Overriding)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被“屏蔽”了。如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。Overloaded的方法是可以改变返回值的类型。
抽象类(抽象类是约束子类必须拥有哪些方法,并不关注子类的实现):
实例:
abstract class A{
public abstract void doSomthing();//定义抽象方法修饰符必须是public(缺省值)或protected
public void fun(){//抽象类中的非抽象方法
System.out.println("Im A.run(),Helllo");
}
}
class B extends A{
public void doSomthing() {//子类必须实现父类的抽象方法
System.out.println("Im B,doSomthing!");
}
public void fun(){
System.out.println("Im B.run(),Hello!");
}
}
class C extends A{
public void doSomthing() {
System.out.println("Im C,doSomthing!");
}
}
public class Test{
public static void main(String[] args) {
A a1 = new B();
A a2 = new C();
B b = new B();
C c = new C();
System.out.println(a1);
System.out.println(a2);
System.out.println(b);
System.out.println(c);
a1.fun();
}
}
抽象类总结:1.包含抽象方法的类一定抽象类,定义了抽象类(abstract class A)不一定有抽象方法,抽象类中也可以定义普通方法;
2.抽象类必须用public或protected修饰;
3.抽象类不能用来创建对象;
4.如果一个类继承了抽象类则子类必须实现父类的所有抽象方法方法。
接口(接口泛指供别人调用的方法或者函数):
实例
interface A{
String s="sd";//接口中变量被隐式的指定为 publin static final
public void doSomething();//接口中所有方法被隐式的指定为public abstract(抽象方法),所以说接口中只有抽象方法
}
interface B{
public void playSomething();
}
class C implements A,B{
public void doSomething(){//实现类必须实现接口所有的方法
}
public void playSomething() {
}
}
接口总结:1.接口中的方法都是抽象方法;2.一个类可以实现多个接口,一个非抽象的类实现了某个接口就必须实现接口中的所有方法(换
句话说:对于遵循某个接口的抽象类,可以不实现该接口中的抽象方法);
抽象类和接口的区别:
以下实例实现了一个会报警门,门的开关是门这一类事物特有的属性,但报警并不是(所有的门并不一定都是会报警的门),报警仅仅可以说是一种行为,一种门可能会有也可能不会有的行为,所以用接口去定义这种行为,你的门有报警功能就去实现(implements)这个接口呗,反之这不去实现。
实例
abstract class Door {
abstract void open();
abstract void close();
}
interface Alarm {
void Alarm();
}
class AlarmDoor extends Door implements Alarm {
public void open() {
System.out.println("来门!");
}
public void close() {
System.out.println("关门!");
}
public void Alarm() {
System.out.println("报警!");
}
}
区别总结:1.抽象类里可以有非抽象方法,而接口内的方法都是抽象的(public abstract);2.抽象类多用来对一类事物共有属性的抽象,接
口只是提供对扩展行为的;3.接口里定义的属性都是final的,接口定义的方法只能是public ;4,一个类可以实现多个接口但只
能继承一个抽象类;
抽象类和接口详解
基本数据类型对应的包装类:byte char boolean short int long float double
Byte Character Boolean Short Integer Long Float Double
目的:把基本数据类型转化成对象类型,java是面向对象的语言,对象类型可以承载更多的信息和操作,另外包装类都实现类Compareable接口可以实现对象之间的比较。
举例:
Integer i = 100;//自动装箱
int t = i;//拆箱,实际进行的操作是 t=i.intValue();
//在运算的时候,也可以进行自动拆箱
Integer i = 100;
System.out.println(i++);
equals() 比较的是两个对象的值(内容)是否相同。
“==” 比较的是两个对象的引用(内存地址)是否相同,也用来比较两个基本数据类型的变量值是否相等。
自动拆装箱详解
java集合类
java集合类中基本的接口:
Collection:是集合类的上级接口,继承与他的接口主要有Set 和List.
List:以特定次序来持有元素,可有重复元素;
Set:无法拥有重复元素,内部排序(无序);
Map:键值对key–value,value可多值
集合类特性(几个常用类的区别)
集合类特性(几个常用类的区别):
ArrayList: 元素单个,效率高,多用于查询 Vector: 元素单个,线程安全,多用于查询 LinkedList: 元素单个,多用于插入和删除 HashMap: 元素成对,元素可为空 HashTable: 元素成对,线程安全,元素不可为空
WeakHashMap: 是一种改进的HashMap,它对key实行“弱引用”,如果一个key不再被外部所引用,那么该key可以被GC回收
Iterator与ListIterator有什么区别
1. Iterator可用来遍历Set和List集合,但是ListIterator只能用来遍历List。
2. Iterator只能正向遍历集合,适用于获取移除元素。ListIerator继承Iterator,可以双向列表的遍历,同样支持元素的修改。比如:增加元素,替换元素,获取前一个和后一个元素的索引,等等。
Collection 和 Collections的区别
Collection是集合类的上级接口,继承与他的接口主要有Set 和List.
Collections是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作
ArrayList和Vector的区别
ArrayList与Vector主要从二方面来说.
一.同步性:
Vector是线程安全的,也就是说是同步的,而ArrayList是线程序不安全的,不是同步的。
二.操作:
由于Vector支持多线程操作,所以在性能上就比不上ArrayList了。
三.数据增长:
ArrayList和Vector都有一个初始的容量大小,当存储进去它们里面的元素个数超出容量的时候,就需要增加ArrayList和Vector的存储空间,每次增加存储空间的时候不是只增加一个存储单元,是增加多个存储单元。
Vector默认增加原来的一倍,ArrayList默认增加原来的0.5倍。
Vector可以由我们自己来设置增长的大小,ArrayList没有提供相关的方法。
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class IODemo {
/**
* @param 把数组写入到文件中
* @throws IOException
*/
public void writerFile() throws IOException{
String str = "";
FileOutputStream fos = new FileOutputStream("result.txt");
OutputStreamWriter osw = new OutputStreamWriter(fos);
BufferedWriter bw = new BufferedWriter(osw);
int [] myIntArr = new int[]{10,-2,5,44,6,-10};
for(int i=0;i1;i++){
str+=myIntArr[i]+",";
}
str = str.substring(0,str.length()-1);
bw.write(str);
bw.close();
}
public void readFile() throws IOException{
String str1 = "";
String str = "";
FileInputStream fis = new FileInputStream("result.txt");
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(isr);
//从文件中读出字符串
str = br.readLine();
//将字符串转换成数组
String[] myStrArr = str.split(",");
//把String数组转换成int数组
int[] myIntArr = new int[myStrArr.length];
for(int i=0;ifor (int i = 0; i < myIntArr.length; i++) {
str1 += myIntArr[i]+",";
}
str1 = str1.substring(0, str1.length()-1);
System.out.print(str1);
br.close();
}
public static void sort(int[] data){//从小到大(冒泡排序)
int temp =0;
for(int i=0;ifor(int j=i+1;jif(data[i]>data[j]){
temp=data[j];
data[j]=data[i];
data[i]=temp;
}
}
}
}
public static void main(String[] args) throws Exception {
new IODemo().writerFile();
new IODemo().readFile();
}
}
基本概念:
进程是程序(任务)的执行过程,说明1.进程是动态的2.它持有资源(内存。。。)和线程
线程是进程的一个执行序列,是系统中最小的执行单元,一个进程可以有多个线程,线程共享进程的资源。
互斥和同步
创建线程的三种方式和常用方法:
①继承Thread类
class MyThread extends Thread {
private int ticketsNum = 5;
private String name;
public MyThread(String name){
this.name = name;
}
public void run() {
while(ticketsNum>0){
ticketsNum--;
System.out.println(name+"卖了1张票,剩余票数为:"+ticketsNum);
}
}
}
public class TicketsThread {
public static void main(String[] args) {
MyThread mt1 = new MyThread("窗口1");
MyThread mt2 = new MyThread("窗口2");
MyThread mt3 = new MyThread("窗口3");
//启动线程
mt1.start();
mt2.start();
mt3.start();
}
}
②.实现Runnable接口
class MyThread implements Runnable {
private int ticketsNum = 5;
public void run() {
while (ticketsNum > 0) {
ticketsNum--;
System.out.println(Thread.currentThread().getName() + "卖了1张票,剩余票数为:" + ticketsNum);
}
}
}
public class TicktesRunnable {
public static void main(String[] args) {
MyThread mt = new MyThread();
//创建三个线程
Thread th1 = new Thread(mt,"窗口1");
Thread th2 = new Thread(mt,"窗口2");
Thread th3 = new Thread(mt,"窗口3");
//启动三个线程
th1.start();
th2.start();
th3.start();
}
}
③.应用程序可以使用Executor框架来创建线程池
比较:Runnable方式可以避免Thread方式由于Java单继承特性带来的缺陷;Runnable的代码可以被多个进程(Thread实例)共享,适合于对个线程处理同一资源的情况
线程在执行过程中,可以处于下面几种状态:
就绪(Runnable):线程准备运行,不一定立马就能开始执行。
运行中(Running):进程正在执行线程的代码。
等待中(Waiting):线程处于阻塞的状态,等待外部的处理结束。
睡眠中(Sleeping):线程被强制睡眠。
I/O阻塞(Blocked on I/O):等待I/O操作完成。
同步阻塞(Blocked on Synchronization):等待获取锁。
死亡(Dead):线程完成了执行。
线程的生命周期
创建状态:当New出一个Thread后就进入了创建状态
就绪状态:创建了线程后,调用了线程的start()方法(注意:次数线程只是进入了线程队列,等待获取CPU服务,具备了运行条件但不一定真正运行了);
运行状态:一旦线程获得了CPU资源,便进入运行状态,就开始执行run()方法里面的逻辑;
阻塞状态:一个正在执行的线程由于某些原因暂时让出了CPU资源,暂停了执行便进入了阻塞状态,如调用了sleep()方法;
终止状态:线程的run()方法执行完毕,或者线程调用了stop()方法(该方法被淘汰),线程便进入终止状态;
互斥与同步
线程间协作:wait() notify() notifyAll()详解
public class Test {
public static Object lock = new Object();
static class Thread1 implements Runnable{
public void run() {
synchronized (lock) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程:"+Thread.currentThread().getName()+"获取了锁");
}
}
}
static class Thread2 implements Runnable{
public void run() {
synchronized (lock) {
lock.notify();
System.out.println("线程:"+Thread.currentThread().getName()+"调用了lock.notifyAll()");
}
System.out.println("线程:"+Thread.currentThread().getName()+"释放了锁");
}
}
public static void main(String[] args) {
Thread1 t1 = new Thread1();
new Thread(t1,"线程1").start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Thread2 t2 = new Thread2();
new Thread(t2,"线程2").start();
}
}
同步与互斥的实现 synchronized(intrinsic lock),synchronized也可以修饰方法,给代码加上锁,禁止其他访问保证只有一条能访问
如何理解加锁互斥,如何理解同步
class MyThread implements Runnable {
private int ticketsNum = 100;
public synchronized void run() {
while (ticketsNum > 0) {
ticketsNum--;
System.out.println(Thread.currentThread().getName() + "卖了1张票,剩余票数为:" + ticketsNum);
}if(ticketsNum <= 0){
System.out.println("票已售完!!");
}
}
}
public class TicktesRunnable {
public static void main(String[] args) {
MyThread mt = new MyThread();
//创建N个线程
/*for(int i=0;i<10;i++){
new Thread(mt,"窗口"+i).start();
}*/
new Thread(mt,"窗口1").start();
new Thread(mt,"窗口2").start();
new Thread(mt,"窗口3").start();
}
}
守护线程(运行在后台,为其他前台线程服务)
特点:一旦所有的用户线程都结束运行,守护线程会随JVM一起结束工作
应用:数据库连接池中的监测线程;JVM虚拟机启动后的监测线程
最常见的守护线程:垃圾回收线程
怎么设置守护线程:调用Thread类的setDaemon(true)方法来设置当前的线程为守护线程(注意事项:setDaemon(true)必须在
start()方法之前调用;守护线程中产生的新线程也是守护线程;并不是所有的任务都可以分配给守护线程来执行,
比如读写操作和计算逻辑)
class DaemonThread implements Runnable{
public void run() {//线程运行的方法
System.out.println("进入守护线程"+Thread.currentThread().getName());
try {
writeToFile();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("退出守护线程"+Thread.currentThread().getName());
}
private void writeToFile() throws Exception {//向文件中写数据的方法
File fileName = new File("c:"+File.separator+"daemo.txt");
OutputStream os = new FileOutputStream(fileName,true);
int count = 0;
while(count<999){
os.write(("\r\nword"+count).getBytes());
System.out.println("守护线程"+Thread.currentThread().getName()+"向文件中写入了word"+count++);
Thread.sleep(1000);
}
}
}
public class ShouHuThread {//测试类
public static void main(String[] args) {
System.out.println("进入主线程"+Thread.currentThread().getName());
DaemonThread daemonThread = new DaemonThread();
Thread thread = new Thread(daemonThread);
thread.setDaemon(true);
thread.start();
Scanner sc = new Scanner(System.in);
sc.next();//没有键盘操作是主线程就会被阻塞,当键盘有输入时主线程就会解除阻塞继续执行直到结束,主线程(唯一的用户线程)结束后,守护线程也会退出运行,所以读写操作就不完整了
System.out.println("退出主线程");
}
}
.什么是死锁(deadlock)?
两个进程都在等待对方执行完毕才能继续往下执行的时候就发生了死锁。结果就是两个进程都陷入了无限的等待中。
如何确保N个线程可以访问N个资源同时又不导致死锁?
使用多线程的时候,一种非常简单的避免死锁的方式就是:指定获取锁的顺序,并强制线程按照指定的顺序获取锁。因此,如果所有的线程都是以同样的顺序加锁和释放锁,就不会出现死锁了。
线程入门实例:
package com.zte.concurrent.base;
/*
* 军队线程类
*/
class ArmyRunnable implements Runnable {
//volatile保证了线程可以正确的读取其他线程写入的值
//可见性 ref JMM,happens-before
volatile boolean keepRunning = true;
public void run() {
while (keepRunning) {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + "进攻对方["
+ i + "]次");
Thread.yield();
}
}
System.out.println(Thread.currentThread().getName() + "结束了战斗");
}
}
/*
* 关键人物线程类
*/
class KeyPersonThread extends Thread {
public void run() {
System.out.println(Thread.currentThread().getName()+"开始了战斗");
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "关键人物杀入隋军["
+ i + "]次");
}
System.out.println(Thread.currentThread().getName()+"结束了战斗");
}
}
/*
* 舞台类
*/
class Stage extends Thread {
public void run() {
System.out.println("欢迎观看隋唐演义!");
try {
Thread.sleep(3000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.println("大幕徐徐拉开");
try {
Thread.sleep(3000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.println("话说隋朝末年,隋军与农民军杀得昏天暗地!");
try {
Thread.sleep(2000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
ArmyRunnable aramTaskOfSuiDynasty = new ArmyRunnable();
ArmyRunnable aramTaskOfRevolt = new ArmyRunnable();
// 使用Runnable接口创建线程
Thread aramOfSuiDynasty = new Thread(aramTaskOfSuiDynasty, "隋军");
Thread aramOfRevolt = new Thread(aramTaskOfRevolt, "农民起义军");
// 启动线程,让军队开始作战
aramOfSuiDynasty.start();
aramOfRevolt.start();
// 舞台线程休眠,大家专心观看战斗
try {
Thread.sleep(20);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("半路杀出了个程咬金!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
Thread mrCheng = new KeyPersonThread();
mrCheng.setName("程咬金");
System.out.println("程咬金的理想就是结束战争,是百姓安居乐业!!!");
// 军队停止作战
aramTaskOfSuiDynasty.keepRunning = false;
aramTaskOfRevolt.keepRunning = false;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mrCheng.start();
try {//join方法调用其他所有的线程都会等待调用join方法执行完
mrCheng.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("战争结束,人民安居乐业,程咬金实现了积极的认识理想。");
System.out.println("谢谢观看隋唐演义,谢谢!");
}
public static void main(String[] args) {
new Stage().start();
}
}
单例模式(保证整个应用程序中某个类只有一个实例):
使用场景:有些对象只需要一个就够了:配置文件,工具类,日志对象,线程池,缓存
定义一个类,它的构造方法是私有的,有一个私有的静态的该类的变量在初始化的时候就实例化,通过一个公有的静态的方法获取该对象。
两种实现方式:
//单例模式的第一种形式---饿汉模式
public class Singleton01 {
// 1.私有的构造方法,目的:不允许外部直接创建对象Singleton01 s01 =new Singleton01();
private Singleton01() {
}
//2.创建类的唯一实例,使用private static修饰
private static Singleton01 instance = new Singleton01(); //当类加载的时候,这个实例就被创建了
// 3.提供一个公有的获取实例的方法,使用public static(加上static让这个方法变成类方法)
public static Singleton01 getInstance() {
return instance;
}
}
public class Test(){
public static void main(String[] args){
//Singleton01 s01 = Singleton01.instance;//通过 类名.成员名的方式创建实例(当创建的唯一实例被private修饰后这种方法就不能创建实例了)
//Singleton01 s02 = Singleton01.instance;
Singleton01 s03 = Singleton01.getInstance();
Singleton01 s04 = Singleton01.getInstance();
if(s01==s01){
System.out.println("是同一个实例");
}else{
System.out.println("不是同一个实例");
}
}
}
改进后的单例模式:
//单例模式的第二种形式---懒汉模式
public class Singleton02 {
// 私有的静态的类变量
private static Singleton02 instance = null;
// 私有的构造方法
private Singleton02() {
}
// 静态的公有的方法
public static Singleton02 getInstance() {
if (instance == null) {
instance = new Singleton02();
}
return instance;
}
}
饿汉模式在类被加载的时候就将自己实例化了,从资源利用率的角度来说,懒汉单例比饿汉单例的效率更高。
工厂模式
概念:用工厂方法代替new,实例化对象;工厂模式包括工厂方法模式和抽象工厂模式,抽象工厂模式是工厂方法模式的扩展
工厂模式的意图:定义一个借口来创建对象,但是让子类来决定哪些类需要被实例化,工厂方法把实例化的工作推迟到子类中去实现;
什么情况下适合工厂模式?有一组类似对象需要创建;在编码是不能预见需要创建那种类的实例,系统需要考虑扩展性,不应依赖于产品类实例如何被创建、组合和表达的细节。
实例:
/*
* 接口类
*/
interface HairInterface {
public void draw();
}
/*
* 实体类1
*/
class LeftHair implements HairInterface {
public void draw(){
System.out.println("左偏分");
}
}
/*
* 实体类2
*/
class RightHair implements HairInterface {
public void draw(){
System.out.println("右偏分");
}
}
/*
* 工厂类提供三种工厂方法
*/
class HairFactory {
//第一种:机械重复的对比之后直接new出对应的类(如果新添加一个类还要重写该方法)
public HairInterface getHair(String key){
if("left".equals(key)){
return new LeftHair();
}else if("right".equals(key)){
return new RightHair();
}
return null;
}
//第二种:通过java的反射找到相应的类(这里需要输入类的完整路径名:com.sunny.project.rightHair诸如此类。。)
public HairInterface getHairByClass(String className){//根据类名来生成对象(java的反射)
HairInterface hair = null;
try {
hair = (HairInterface) Class.forName(className).newInstance();
} catch (InstantiationException | IllegalAccessException
| ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return hair;
}
//第三种:根据类名来生成对象(通过读取配置文件,找到相应的类名进行实例化,这样在增加类的时候大大简化了操作)
public HairInterface getHairByKey(String Key){
HairInterface hair = null;
try {
Map map = new PropertiesReader().getProperties();
hair = (HairInterface) Class.forName(map.get(Key)).newInstance();
} catch (InstantiationException | IllegalAccessException
| ClassNotFoundException e) {
e.printStackTrace();
}
return hair;
}
}
/*
* prrperties文件的读取工具类
*/
class PropertiesReader {
public Map getProperties() {
Properties props = new Properties();
Map map = new HashMap();
try {
InputStream in = PropertiesReader.class
.getResourceAsStream("type.properties");
props.load(in);
Enumeration en = props.propertyNames();
while (en.hasMoreElements()) {
String key = (String) en.nextElement();
String property = props.getProperty(key);
map.put(key, property);
}
return map;
} catch (Exception e) {
System.err.println("不能读取属性文件. "
+ "请确保db.properties在CLASSPATH指定的路径中");
}
return null;
}
}
/*
* 测试类
*/
class SunyTest {
public static void main(String[] args) {
HairFactory factory = new HairFactory();
HairInterface hair = (HairInterface) factory.getHairByKey("right");
hair.draw();
}
}
配置文件type.properties
left=com.sunny.project.LeftHair
right=com.sunny.project.RightHair
实例总结:
该实例共有接口类、实体类、工厂类、工具类(提供从配置文件读取数据的方法)、测试类这5种类,其中工厂类提供了三种工厂方法实例化对象的方法,第三种方法在新添加一个实体类的时候修改的代码最少(只需要新建一个实体类然后在配置文件上加上该类就OK了)
抽象工厂模式