public class HelloWorld{html
//static: 经过类找到此main方法并调用java
//public: 使得JVM能找到并使用此main方法react
//void: JVM不须要返回值sql
public static void main(String[] args){数据库
//定义一个String类型局部变量 变量名为 s编程
String s;小程序
s=”HelloWorld”;设计模式
//这里调用System.out(输出流)的println()时会自动调用已经覆写了的toString(),因此输出的结果不是对象的地址而是对象的值。数组
System.out.println(”s said:”+s);浏览器
}
}
文字解析HelloWorld
字符串数组 String[] ,堆中有的是空数组对象,new String[0] 中有对象可是没有值。GC做用于堆。
代码区包括类代码和共享代码,数据区包括静态数据区也叫常量池和缓冲数据区(包括整型 Integer -128~+127 ,字符串对象)
栈中的方法执行空间包括断点调试,临时变量,数据局部变量等等。
主类public是编译器的入口,主方法main是JVM的入口。
String 与 String[] 是两个不一样的类
20142023 软件1412段飞霞
C语言的缺点:内存须要本身去管理,变量不赋值会致使系统崩溃指针太麻烦;优势是效率高。
Java的缺点:Java以牺牲效率为代价来提升安全性,自动释放内存。
Java中通常只有一个主类是公有(public),其余的类都是默认的。
静态的继承编译时知道,动态的继承执行时才知道。
Java支持多平台的缘由:
一、Java是先编译再解释。
二、JVM的上层模块相同,下层与系统相接的地方不一样。
三、JVM(虚拟机)的个数与系统的个数相同。这就是一次编写处处运行的缘由。JVM是相同的,而后将.Class文件解释为相应的机器指令。
在编译与解释中,.java与.class文件都不会变化,JVM是变化的。
Java源代码与字节码与机器无关,JVM与机器有关。
JVM是由硬件和软件模拟的计算机
关于GC(垃圾回收机制)
GC:垃圾回收机制,优势是更好的回收使用内存,缺点是效率不高。
内存泄漏是指内存使用不当致使系统崩溃。
Java的GC机制只能适当的改善问题,不能避免内存泄漏问题。
环境变量配置的缘由:
一、Path:……bin,找到java javac等命令
二、Classpath:……lib,找到标准库中的类(不能省略)
三、JAVA_HOME:针对tomcat配置的,肯定jdk的位置。
JVM的内存:
方法区:分为代码区和数据区。
堆:堆中通常存放对象,对象都有属性和方法(通常都有四个字节)
栈:栈中主要包括形参,局部变量,断点,堆空间的地址,方法区空间的地址以及临时数据。
实例方法经过对象调用
除了常对象在方法区的常数据区中开辟空间,其余的对象都在堆中开辟空间。
Applet(java应用小程序)
Applet:是不安全的,容易被黑客入侵,程序由浏览器执行
HTML是静态的,可是存储在服务器上而后下载到浏览器上由浏览器执行。
1+1<2 的原理是模块化
一个程序只要有主类 public修饰的类就能够被编译生成.class文件
面向对象:
面向对象的概念:以对象为核心,属性与需求都会有变化,可是对象不会变,从而保证程序的正确性和可维护性。
对象是把事物放在问题领域中抽象出它的方法。
对象与对象之间的关系主要有两种:继承和关联(一对一,一对多,多对多)
普通类默认继承Object类
类与属性之间的绑定经过this关键字
参数签名:参数类型,参数个数,参数顺序
封装:是指用共有方法操做私有属性
构造方法:
构造方法没有返回值类型可是会有参数签名。没有return
构造方法在类中能够有多个,单例的构造方法是私有的
建立一个对象时会调用多个构造方法(this)
若是有父类,则也会调用父类的构造方法(super)
抽象类有构造方法可是接口中没有构造方法
构造方法是由JVM来调用的,不是经过对象调用
构造方法有无数个,可是无参的构造方法有且只有一个。
通常类的访问权限分为两种:public和 default
构造方法的做用:为堆里面的对象的实例全局变量赋初值(初始化)
不能经过this来调用构造方法,可是调用构造方法必定要传this指针
建立对象先默认初始化再调用构造方法初始化:
建立对象的第一步在堆里开辟空间,首先开辟属性空间再开辟方法空间再默认初始化。基本类型值为0,引用类型为null,再进行构造方法的初始化
调用构造方法必定要给对它传对象的地址,构造方法不能是静态的
方法在堆中开辟空间,经过对象调用,开辟屡次空间
结构化程序设计就是面向过程的意思。(模块化)
C语言是以函数为单位
架构师分句需求分析创建基本架构,通常是用MVC的三层架构,流程图主要用于详细设计。项目的成败决定于需求的获取。
对象的属性:
经过公有的方法对私有属性进行访问,能够对用户传送的数据进行约束。
属性或者域都是指在类里面定义的变量,通常都用private,外部不能直接访问
属性开辟空间的大小和数据类型有关,方法通常都是四个字节
初始化过程分为两次:调用构造方法时为对象的属性和方法初始化
默认初始化(普通数据默认为0,引用类型的数据为null)
this指针是指对象的地址,对象的值,对象没有名
实例方法存在于方法区的共享代码段,堆中存放的是实例方法的引用或地址
调用构造方法不必定会建立对象,可是建立对象必定会调用构造方法。
抽象类与接口中均可以定义属性
静态方法不能传递this指针。
问题一:建立一个对象时为何会调用多个构造方法?
由于此类可能有父类,因此会调用父类的构造方法
问题二:this指针是怎么传递的,它的地址是怎么样的?
虚拟机传递过去的
方法分为:实例方法,主方法,构造方法。
只有对象才能调用实例方法,实例方法只能经过对象调用
编译时不能建立对象,只有在执行时虚拟机才有可能建立对象。
在调用构造方法以前就已经有了对象的地址
实例方法不能直接调用,必定要经过对象调用
主类public是编译入口,主方法main是jvm入口(执行)
封装的做用:隐藏类的实现细节,设定权限,保证数据的完整性,有利于修改与加强代码的可维护性。
方法的重写:是指方法名还有参数签名都和父类一致。
方法的重载:是指方法名相同可是参数签名不一样
包申明:只有字节码文件放在包指定的目录下才能被使用
包导入:指定字节码文件的具体位置
包导入时 * 与.具体类 的执行效率不一样,后者效率高。
包申明只有一个,包导入能够有多个。
当测试类的.class文件与测试类的.java文件不在同一目录下时,执行测试类应加上类的相对路径 例如 javac mypack.Test
在doc命令中带包编译的格式 javac –d . aa.java
this的使用: 当属性名和方法中的变量名重名时,在方法中会优势调用方法中定义的变量,若想调用类中定义的属性应在前面加上this. 表示经过对象调用。
栈中分配空间,调用一个方法会分配一个空间。
信息隐藏:是指把属性定义为私有的,外部不能直接访问。
Java通常经过接口来保证稳定性。
序列化:表示能够存储在硬盘中的数据。(类能够实现序列化接口)
注释分为两种:
说明性注释:(类的做用,做者,版本,日期,接口)
功能性注释:(某属性,代码的功能)
对类的注释:类的做用,做者,版本
对方法的注释:方法的做用,参数,返回值,异常
Javadoc:收集对类的注释,在命令行中:javadoc A.java ,会根据注释生成一系列的文件,以index.Html为入口查看。
Java类的通常只有public和默认类型,接口也是这样。
Javadoc收集的注释是对public类型的方法以及默认的方法的注释。不包括protected和private类型的注释。
Javadoc –private Test.java//收集对全部类型的方法的注释
Javadoc –private –version –author Test.java//收集全部方法的注释以及程序版本和做者
标识符包括:字母,下划线,$,_,以及数字(可是数字不能用于开头)
汉字能够做为标识符: Strirng 你好=null;//是合法的
标识符不能定义为关键字或者标准类库中的类
关键字:
boolean: 1个字节,用于关系判断和逻辑判断
byte:1个字节, -128~127
short:2个字节,-32768~32767
long:8个字节 int:4个字节
float:有效位数为8位 double:有效位数为15位
abstract:能够用来修饰类或方法,能够被继承可是不能本身建立对象
assert:断言,没有通过验证的结果
break:跳出本层循环 continue:跳出本次循环,开始下一次循环
final:定义的类不能被继承 定义的方法不能被重写只能重载 定义属性只能初始化,不能赋值
new关键字的最终目的是返回对象的地址
super:标明父类的特征,经过this去找到父类的对象
throw:抛异常 throws:声明异常
transient:瞬时状态
A :字符型 ‘A’ 十进制 65 十六进制 41(16) Unicode ‘\u0041\’
A:字符型 ‘a 十进制 97 十六进制 61(16) Unicode ‘\u0061\’
回车符 : 字符型 ‘\r ’ 十进制 13 十六进制 d(16) Unicode ‘\u000d\’
换行:字符型 ‘\n’ 十进制 10 十六进制 a(16) Unicode ‘\u000a\’
空格:字符型 ‘ ’ 十进制 32 十六进制 20(16) Unicode ‘\u0020\’
Java只有值传递,没有地址传递。
Java.Lang:包括 throws ,Exception, Math, String, System ,Integer
一个8进制数至关于三个二进制数
一个16进制数至关于四个二进制数
不一样数据类型之间的转换原则:
当数据中有double类型时,结果必定为double类型
当整形数据与实型数据进行运算的时候,结果应该为实型数据
Byte char short 数据类型的数据进行运算结果为int型
双目运算会改变运算量的类型,单目运算和复合赋值运算不会改变运算变量的类型,
i+=1//逆波兰式 复合赋值 f_abc//匈牙利变量命名规则用下划线链接
int a=(int)1.567;//造型,向下转型
数值尽可能不要用造型容易形成数据丢失
引用类型:必定与对象关联 存放的是对象的地址而不是对象自己
声明时不会建立对象,只会分配引用空间
Javac *.java//一次编译当前包下的全部.java文件
编译时会对全部的语句进行检查,无论是否被调用到
通常不要在普通方法中建立对象,由于这样容易引发内存泄漏
实例全局变量:在堆中开辟空间,对象建立时开辟,有默认的值,构造方法会为实例全局变量初始化 建立几回对象就会被建立几回,对象调用,空间在对象消失时销毁gc
静态全局变量:具备全局性,该属性归该类全部对象公有,没有this指针,通常经过类使用也能够经过对象调用
静态全局变量的内存空间是固定的一块,被修改后,日后的引用的值都会一块儿被修改
实例全局变量只能对对象调用,局部变量只能由方法调用,静态全局变量能由方法,类,对象调用。
静态全局变量:
静态全局变量加载时在类的方法区的静态数据区开辟一次空间,构造方法不对静态变量初始化,而且静态变量没有this指针,不使用对象调用可是每一个对象都对它能够有引用,静态变量的生存周期和程序的同样,通常不会被释放。
静态数据和类的关系叫关联(属性与类)
动态和类的关系叫绑定(方法与类)
Java没有真正的输出地址,除非复写了hashcode toString方法,当你拿到对象的地址时,JVM会自动的经过地址找到对应的值输出。
在同一个类中,加载此类时,为静态全局变量的开辟内存空间比为main()开辟空间早
局部变量存储在栈中,没有初始化是不会有默认值,全局变量有默认值
形参是指函数申明时的参数,实参是程序运行过程当中实际调用此函数的时候给它传递的参数
传值:形参(方法中的参数)的变化不会影响实参(局部变量)的变化。由于形参和实参不在同一个工做空间,形参在栈中的空间 本方法执行后就消失了。全部的方法工做空间(栈桢)在方法执行后就自动释放了。
没有特殊状况尽可能不要定义静态变量和静态方法(单例除外),由于会参加维护成本
调用其余类时能够不导包,可是写类的全路径名 例如 java.lang.Math
JVM的输出机制:内部有个valueOf()方法,先判断对象是否是null,若是是就直接输出null,若是不是就调用toString()输出对象的值。
只有属性没有方法的对象叫贫血模型
只有方法没有属性的模型叫充血模型
在方法中,若是变量名冲突,会优先使用方法中的形参(栈中开辟的空间 局部变量)
主方法与实例方法用了同名变量,被调方法改变变量,main( )中变量值也变
在普通方法中建立对象,方法调用完内存释放后 对象会变成游离状态,容易形成内存泄漏(尽可能不要在普通方法中建立对象)
方法内部中优先在本身的栈工做空间找变量,找不到再经过对象找
实例变量能够与局部变量同名,可是实例变量与实例变量不能同名
重载时根据参数签名来调用方法
普通类型传值时,形参改变,实参不变
引用类型,传值时,形参改变,实参也变
Class Test{
int ab=12;
public void setAb(int ab){//形参
ab=ab;//ab的值为形参的值
System.out.println(ab);//11
System.out.println(this.ab);//12
}
Main(){
Test t=new Test();
t.setAb(11);
}
}
数据的运算:
除法:
整形数据除以0,//算术逻辑异常,ArithmeticException(12/0,,0/0)
浮点型数据的运算:
浮点型数据除以0,或者整形数据除以0.0,结果为Infinity(1/0.0 3.0/0, 3.0/0.0 -1/0.0 )
当 0/0.0 : NaN (Not a Number)
取余: 被除数小于除数,结果为被除数 17%18 = 17
17%0 : ArithmeticException
17%0.0 1.3%0 -1.3%0 :NaN
17.6%4 整数部分照常取余,小数不变
17.6%4.2 不出错,单数结果不同 17%4.6 也是同样
位运算:
可以参与 位运算的数据类型包括; int short long char byte
>>右移,至关于除以2
<<左移,至关于乘以2
Java经常使用的是循环右移
循环右移的位数为: int n ,a ; a>>n 当n>32 时 n=n%32; a 右移n%32位
Long n,a, a>>n 当 n>64时,n=n%64,a 右移 n%64位
字符串运算:
X 和y都是 int类型数据时
System.out.println(“”+x+y);//生成5对字符串对象
“” / “”+x / “”x / y / “”xy
Sytem.out.println(x+y+””);//生成3个字符串对象
Xy / “” / xy””
数据的比较:
在引用类型中 equals比较对象的类型再比较对象的值
在基本类型中直接比较值
==号用来比较数值
基本类型只能用==来比较
&&短路与运算:当逻辑表达式有一个值为假时,则再也不计算后面的表达式,直接给出值
||短路或运算:当逻辑表达式有一个为真时,则再也不执行后面的表达式,直接给出值
Java只给四个类复写了toString方法,(没复写的会调用==)
File Integer String Date
Integer对象在 -128~127之间会把对象建立在常量池中,相同的引用只建立一个,后来的先判断是否存在,存在的话直接调用,不然建立。
除了(-128~127)之外的Integer对象在堆中建立对象
Null不能调用 equals方法,不然会出现NullPointException
从表单中获取的数据不可能为null,只会出现“”空串和字符串
Switch能够接收的数据类型:int char byte short
在循环条件为真时,while 和 do while{} 执行的次数是同样的 ,当循环次数为假时,while 不执行 do while执行一次
非正常出口跳出循环:
break:跳出本层循环
continue:结束本次循环,开始下一次循环
Label标记:标识循环体
inner: for(){} break inner;//表示跳出label所标记的那层循环
标识符直接写在循环体上面,命名规则和变量名相同
int k =System.in.read();//从键盘缓冲区中读取一个字符
例: 输入 a 回车, 会读出三个字符 97 ‘\r’ ‘\n’(10)
continue label :结束label所标识的那层循环的本次循环,开始那层循环的下一次循环。
数组和变量:
变量的空间不连续,数组的空间是连续的
数组的空间叫元素名
变量寻址:自动建立变量名 自动映射表 直接寻址
数组元素寻址: 间接寻址(根据下标来寻址)
数组没有复写toString (),输出的是地址
数组:存放数据的容器,长度固定 类型同样
给数组对象赋值: String[] str={“1”,”2”};//1个变量,两个对象
数组的主要应用是排序: 插入排序 冒泡排序 堆排序 选择排序 快速排序
冒泡排序:两两比较,大的数据日后
选择排序:选择一个元素和其余元素比较,比它大的不变,小的交换位置
插入排序:第一个数肯定位置 后来的数都和第一个比较 大的数位置不变,小的数放前面
Int[] a=new int[5];//1个变量,5个元素,每一个元素为int类型
Int[][] b=new int[3][];//1个变量,1个int[][]对象 3个int[]对象,9个元素
使用new来建立多维数组的时候,只须要指明最左边的大小
Int[][][] a=new int[3][][];//3个元素,每一个元素都是int[][]类型
多维数组就是数组当中的数组
类的继承:
父类的构造方法和私有属性和私有方法不会被子类继承
Java是单继承,多实现的类
继承关系中,建立子类对象时不会建立父类的对象,可是会调用父类的构造方法
调用子类的构造方法,父类中的构造方法中传递的是子类的地址
哈希地址: 前面是类型 +后面是地址
为何建立子类对象要调用父类的构造方法?
由于子类须要调用父类中私有的属性和方法,须要父类的构造方法为之初始化并与父类创建动态绑定便于父类引用型变量调用
编译时的绑定为静态绑定
向上转型:父类引用型变量指向子类,父类引用型变量只能看到子类继承的和覆盖的方法,看不到子类新增的方法和属性 只能经过静态绑定找到类,再经过类的动态绑定找到属性
建立子类对象的机制?
在堆里面为父类的私有属性和方法开辟空间和父类进行动态绑定
在堆里为子类的方法和属性开辟空间(静态绑定父类的和子类新增的)
重载:方法的重载是在同一个类中,参数签名不一样(对返回值类型访问权限没有要求)
抽象方法能够被重载,main方法能够被重载,static方法能够重载为非静态方法
JVM在编译的时候就已经知道该调用哪一个方法,这叫静态多态,编译多态
覆盖:是指在两个类中,有继承关系,子类继承了父类的方法才能覆盖,而且子类对父类方法的覆盖只能有一次
覆盖准则:出如今两个有继承关系的类中,方法名和参数签名必须相同,返回值类型相同,子类的访问权限不能比父类的访问权限更严格,必定要大于父类的访问权限
Java中子类对父类的实例方法的重写叫覆盖,对是static 方法的重写和对属性的重写叫隐藏
造型:必定是两个类,而且存在继承关系,要有向上转型(造型的效果只是临时性的,只是把变量的值改成理想型)
访问权限的控制: private(本类) default(包) protected(子类) public(所有)
关联和绑定:
关联:与静态方法静态属性的关联 没有绑定this指针
静态关联:编译时类和方法的关联
动态关联:加载时 类与静态全局变量的关联
绑定: 与构造方法实例方法的绑定有this指针
动态绑定:与私有属性和私方法的绑定
继承关系中: 先在堆中为父类的私有属性和方法开辟空间 与父类进行动态绑定,父类中的实例方法与父类静态绑定,覆盖后的方法和子类静态绑定。
建立对象
建立对象时会先调用父类的构造方法在调用子类的构造方法,在父类里面定义的方法被子类调用时会看不到子类中新增的方法。子类引用型变量调用继承父类中的方法时,没法找到子类中新增的同名方法,因此会先调用父类的方法
Super:是用来找到和父类动态绑定的私有属性和方法
Super的特色:
是父类的一种特征。
只能使用在实例方法中
不能用在static(静态)方法中
经过super找到父类的绑定的方法,在经过父类的动态绑定找到父类的私有属性
Super:在构造方法中的做用是显示的调用父类的哪一个构造方法,出如今指定构造方法的第一条语句,只能有一条 super(); 参数填在括号中,调用父类无参构造方法时,就不写参数。 默认调用父类无参的构造方法。
普通类的权限只有默认的和public ,内部类什么权限都有
继承关系中,父类不提供可供子类访问的构造方法时,子类对象没法建立(建立子类对象必定有调用父类的构造方法)
能够在子类的有参构造方法中,经过使用super调用父类的有参数的构造方法
this:表明其所在类的当前对象的引用
this在类中构造方法中的做用:指定调用本类的某个构造方法
没有继承关系时,建立对象也可能调用多个构造方法 this指定
this和super不能出如今同一个构造方法中
初始化块:做用和构造方法类似,给类的变量赋初值 (仅给定义在初始化块以前的变量初始化) 比构造方法调用的早 会传递this指针
建立对象的执行顺序:
一、 先给类中的静态属性开辟空间
二、 再给属性和实例方法开辟空间
三、 调用初始化块为之初始化
四、 而后再调用构造方法进行初始化
建立几回对象就会调用几回初始化块语句
WapperClass//封装类:
封装类 : Boolean Character的父类是Object //没有valueOf()方法
Integer Byte Short Long Float Double BigDecimal 的父类是Number 均可以调用valueOf()
封装类都是final类型,不能被继承
封装类的构造方法 :
以基本类型数据为参数的构造方法
以基本类型数据字符串的形式构造方法
Integer i=new Integer(10); 等价于 Integer i=new Ingeter(“10”);
int ii=i.valueof();等价于 int ii=Integer.valueOf(i);
封装类复写了toString()方法和 equals()方法
toString() 表示返回这个对象的字符串,每一个类都有toString()方法
封装类 异常 集合 date 网络复写了toString()
Object 的toString() ,
this.getClass().getName+“@”+Integer.toHexString(hashCode());
获得对象的地址的方法,Integer.toHexString(hashCode());
实际开发中复写的tostring()
Public String toString(){
return this.getclass()+”[name”+name+”age”+age+”]”;
}
在调用toString方法时,会先调用valueOf 方法,判断对象是否为null,为null的时候直接输出null,不为null的时候才会调用toString()
Object中的valueOf( ):
Public static String valueOf(Object obj){
return (obj==null)?”null”:obj.toString();
}
任何类都有equals方法,object 中的equals方法直接调用==
本身复写equals方法:
1判断被比较的对象是否为null
2 判断对象是否相等==
3 判断类型是否一致 p.getClass()
4 判断类的属性是否相等 须要对对象进行造型
Public boolean equals(Object obj){
if(obj==null) return false;
if(obj==this) return true;
if(this.getClass()==obj.getClass()){
Person p=(Person)obj;
if(p.getName().equals(this.getName()){//String复写了equals方法
return true;
}
}
}
同一个类只有一个反射对象
Static用来修饰类变量 语句块内部类 static不能用来修饰构造器
构造方法不能对Static变量进行初始化,只能由static语句块为静态变量初始化,而且在类中只加载一次
编译的时候不能建立对象,反射对象是加载类的时候建立的
静态方法不属于对象,建立对象时不会为静态方法开辟空间
静态初始化快中没有this指针,静态初始化块在main()以前执行
静态初始化块和初始化块的区别:
一、语法不一样,静态的有static{}
二、 调用机制不一样,静态加载类时调用
三、 执行次数不一样 静态的只执行一次,
相同点:都是为属性初始化
静态用来实现单例,
单例模式的特色:共享数据线程同步项目安全下降并发性,增长耦合性
饥汉式单例:一加载就建立对象,只建立一个对象
Public class Singleton{
Private Singleton(){}//构造方法私有化,让外部只能经过类建立对象
Public static Singleton instance=new Singleton();
Public static Singleton getInstance(){
return instance;
}
}
饱汉式单例:第一次使用时 先判断对象是否存在,不存在时在建立,只建立一个对象
Public class Singleton{
Private Singleton(){}//构造方法私有化,让外部只能经过类建立对象
Public static Singleton instance=null;
Public static Singleton getInstance(){
If(instance==null){
instance=new Singleton();
}
return instance;
}
}
推荐使用饱汉式单例模式效率高
final:
1、final 定义的方法能够被继承,可是不能被覆盖
2、final修饰变量只能初始化一次,不能赋值
final static int a =20;//a的值不能再修改了
三、final实例全局变量也只能初始化不能赋值
四、引用类型final定义的实例全局变量不能改变对象,可是能够改变对象的引用 a.name
五、final局部变量若是没有初始化,只能赋值一次
六、方法的形参能够是final类型的,只能初始化一次
七、方法内部类中只能使用final类型的形参
final类不能被继承,final修饰的属性仍是变量不是常量,常量没有初始化,常量不能被赋值
Abstract类中会有构造方法,子类继承abstract类时会调用父类的构造方法建立对象,可是不会建立父类对象
接口:
Interface中没有构造方法,接口中不能有静态初始化快语句
内部类能够保证线程的安全,内部类分为方法内部类也叫局部内部类,实例内部类也叫全局内部类
一个接口能够继承多个接口,可是一个抽象类只能继承一个类
类与接口的关系叫实现
多态是在执行时才知道的,父类引用型变量调用了子类的那个对象
重写是编译时知道的
接口中不能有初始化块和构造方法,接口中定义的变量都是 public final static 类型的
预运算符 : 类名:方法(); 指定使用哪一个类中的那个方法
接口的特色:
一、编译时会生成字节码文件
二、接口中的新增方法也要经过造型来调用,//接口回调
3、接口是一种功能规范,更注重抽象方法,不注重属性
4、接口的功能:下降耦合性,提升可维护性
内部类:
内部类和外层封装它的类之间存在逻辑上的从属关系
内部类能够访问外部类的私有属性
外部类 outer 内部类inner 编译后 outer$inner.class
拥有内部类的外部类对象建立时不要考虑内部类,和正常类同样建立
可是内部类的建立须要考虑外部类
Outer oute=new Outer();
Outer.Inner inner= outer.new Inner();
在外部类的方法中能够自动识别内部类,内部类对象直接拥有对外部类对象的引用
内部类私有时,外部测试类中不能建立内部类对象
外部类方法中能够建立内部类对象,使用内部类
匿名内部类:私有内部类省略名字,外部没法使用
局部内部类:定义在方法中的类 做用空间只在方法中
方法内部类对象不能使用方法内部非final类型的变量
内部类能够声明为抽象类被其它内部类继承,也能够声明为final类型的
Exception:保证程序的健壮性,先处理问题,应对用户需求的变化
Error:错误,是解决不了的问题
RuntimeException:程序自己的异常,还未编译,运行时异常
IOException : 外部资源问题,编译时异常
finally:用于异常处理时关闭资源,finally中最好不要有return语句。
异常处理机制中,有返回值栈,返回值压栈,只返回最后一个return值
Throwable包括Error 和Exception
实际开发中一个try{}能够配多个catch() 最后catch的是 Exception
父类和子类的异常关系,继承后 子类不能比父类声明更多的不处理的异常
子类须要处理的异常必定要比父类多
Throws :表示不处理此类异常,在方法后面申明,程序没有编译错误(throws IOException)
Throw :出如今方法内部,后面只能跟一个异常对象,把异常对象抛出(throw new RuntimeException(e))
Throw能够由系统来写,系统自动检测程序,也能够本身定义异常
方法使用了throws表示把异常 抛给了调用它的方法的对象
系统先在catch中找到throw声明的异常,没找到再去throws中找不处理的异常
Message :由自定义异常类的有参构造方法设值
e.getMessage();公有的获取异常信息的方法
e.toString();显示异常对象的类型,显示message()信息
e.printStrackTrace();调用toString() 找到异常出现的类方法//最详细的显示异常信息
自定义异常类: 1 继承Exception类 2 提供一个无参的和有参的构造方法 super(msg)
不在业务层和持久层处理异常,交给表示层处理异常,业务层直接抛出异常
异常栈的跟踪:从栈顶开始跟踪,一直到异常处理
异常会影响系统的效率,发生异常的位置和捕获异常的位置越近越好
处理异常的原则:
1 解决运行时异常,设定编译异常
2对方法的异常作声明 throws
3捕获异常把异常代码放在try{}中,try中的代码量不能过多
4 catch必定要尽可能和try中的代码一一对应,多个catch对应一个try
5 捕获了异常要处理异常
6 有资源存取时,finally中要有关闭资源的,finally中不要有return语句
命令行参数 在cmd 命令中 编译完A.java 后 在解释时 输入 java A 1 2 3 输入参数
1 2 3 会存入String[] args 数组中
System.exit(1);//手动退出系统
String --.> int :
int age=Integer.parseInt(params);
Java是先编译后解释的语言
标准流: System.out 和System.err 都是PrintStream 对象
System.in 是InputStream对象
System 继承了PrintStream 和 InputStream的父类 (标准流类)
字节流:一次只读取一个字节
字符流:一次读取两个字节,读中文时不会出错,读英文时会自动扩充
Data流和Object流比较重要
Properties其实就是map 以键值对的形式存储数据
通常的key 和 value是Object 类型,Properties的key和value是String类型
建立properties对象 :
Properties props=new Properties();
往properties对象中设定属性:
props.setProperty(“name”,”zhangsan”);
从properties对象中取值
props.getProperty(name);
Properties文件中的key和value课能够用 等号 空格 冒号 分隔开
Properties的对象,内存的存储空间
Properties文件:外存的存储文件
.\\ 表示相对路径
InputStrean in=new FileInputStream(“a.properties”);
props.load(in);//读取配置文件的信息
FileOutputStream fos=new FileOutputStream(“b.properties”);
props.store(fos,name);//将props对象中的数据存储到b.properties文件中 name 为对b.properties文件的说明
Key 不能重复,value能够重复
Java中的系统属性是java的环境变量
Properties props=System.getProperties();//会建立properties对象, 把环境变量中的内容设到props中
Enumeration 枚举类型的迭代
Props.propertyNames();///获取全部的属性名
HasMoreElement();
nexElement();
复习:
Java的起源 94年出现 为网路开发而生。 java的出现推进了B/S模式,面向切面编程理念
Java的应用 –网络应用,应用普遍。
IOS Andriod 不是很流行
Java技术体系架构: J2EE 企业级应用开发
Java的优势:简单,面向对象,健壮,多线程,结构中立跨平台,安全,一次编写处处运行
一次编写处处运行:由于有虚拟机,先编译后运行
垃圾回收机制:GC,对内存的使用有很大的提升,可是没有解决内存泄漏问题(瞬时态和离线态进行回收) 下降了效率 ,是一个后台线程 占用了CPU效率
Applet:字节码文件嵌入到html中,经过浏览器解析执行,浏览器自带虚拟机
程序设计简史:
结构化程序设计:一次性把全部需求找完,相似瀑布模型
面向对象程序设计:以对象为核心,对象是指事务在问题领域中的抽象,核心问题是如何找对象。
面向对象的四大特色:隐藏(private),封装(set/get),多态(父类的方法在子类中的不一样实现),继承
领域模型:经过类抽象出类和类之间的关系
类中叫属性名,对象中叫属性值
构造方法:由虚拟机系统调用,能够被重载,建立一个对象可能会调用多个构造方法,编译时知道调用哪一个构造方法
信息的封装和隐藏:给属性加private,外部提供get、set方法 保证信息的安全性和完整性。
Java源文件的结构:
包申明(package abc):字节码文件必须方法当前包目录下才能使用,体现了分包管理的原则
包导入(import abc.*;):找到指定的字节码文件的位置
Strust1.0 :编码效率低,执行效率高 SpringMVC
Java的注释:是否能够被收集 javadoc 能够收集文档注释 /** */
标识符:不能定义为关键字和标准类库中的类名
Java数据类型 8中基本类型和引用类型
引用类型存放的是对象的地址,不必定在栈中开辟空间,可能在对堆中 或者是方法区中(static在方法区中)
传递方法:只有一种值传递
双目运算符会改变运算量的类型,单目运算不会改变
Set和Map必定要复写equals方法
只有Integer String Date File复写了equals方法
表单中拿到的字符串不会是null(request.getParameter(“name”))
位运算适合的运算类型:int long byte char short
Switch中的数据类型只能是 int byte short char
数组是个容器,是经过类来建立的对象,长度固定
数组存放的数据类型必须一致,查找速度快,插入删除比较慢
空数组没有意义,空集合有意义
链表:插入和删除比较快,查找速度慢
数组是length属性,集合有size(), 字符串有length()
List集合是动态加长的集合数组
继承的特色:单一继承,私有属性和私有方法不能被继承
建立子类对象不会建立父类对象,可是会为父类的属性开辟空间
重载:在一个类中,多个方法名相同,参数签名不一样的方法。编译时识别
主方法和静态方法和抽象方法都能被重载
Java对属性和静态方法的重写叫作隐藏
Java对父类的方法重写叫作覆盖
重写的特色:在两个有继承关系的类,方法名相同参数签名返回值类型相同,访问权限要大,抛出的异常要少(处理的异常必定要多于父类) 抽象方法必需要重写,静态方法能够重写 叫隐藏。
This:当前对象的地址, new对象的时候建立的,(先有this,才调用构造方法),this所指定的属性和方法必定在堆中。
Super:父类的特征,父类绑定的实例属性和实例方法,只能在实例方法中调用。在构造方法中显示指定调用哪一个方法。 Super() 必定在子类的构造方法中的第一句
调用super必定要有this
静态方法中没有this,
初始化快:在构造方法前对在定义初始化块之前的实例全局变量进行初始化,放到最后。建立几回对象调用几回初始化块
静态初始化块:只调用一次,比main方法还早调用
this super 初始化块:
第一步:压栈
第二步:为父类的属性初始化
第三步: 为子类的属性初始化
第四步:调用父类的初始化块初始化
第五步:调用子类的初始化块初始化
第六步:弹出子类的构造方法”
封装类:是一种类型,基本类型的首字母大写 char Character ---- int Integer
封装类的数据结构:都是final类型,复写了toString() 复写了equals()
封装类的对象的建立不能用无参的构造方法,只能有参的
全部的类有都有equals方法,跟==等值比较同样去比较
Static 能够经过类调用,也能够经过类中的任意对象调用
静态属性随意使用会增长耦合性 ,静态方法不能传递this指针,在静态方法中也不能使用super。
静态内部类不能访问外部类的非静态属性
构造方法不能静态(由于没有this)
单例:Singleton (饿汉式)
静态全局变量,private static Student instance=new Student();
构造方法私有化 private Student(){}
静态的公有的public static Student getInstance(){ return instance;}
Singleton (饱汉式)
静态全局变量,private static Student instance=null;
构造方法私有化 private Student(){}
静态的公有的public static Student getInstance(){
if(instance==null){
instance=new Student();
} return instance;
}
缺点:耦合性高,效率低
优势: 安全性高
final: final修饰的类不能被继承,final修饰的变量只能初始化一次。数组类型的引用类型为final类型,数组对象的类型不能改变,final类型的变量不是常量。 方法内部类的形参只能是final类型的
抽象:方法没法实现时,先声明定义为抽象方法。(例:求某个图形的面积和周长)
空方法不算抽象方法,它有空实现。
适配器的特色:把不一样的对象进行统一的处理
多态:动态编译,在接口上常用多态
模板模式:继承
接口:接口中的全部属性是 public static final 类型的 ,一加载接口字节码的时候就初始化,在方法区开辟空间
接口中的全部方法是public abstract类型的
接口不是类,更不是特殊的抽象类
接口语法: interface定义,
一个子类只能够extends 一个父类,抽象类有构造方法,可是不能建立对象,接口没有构造方法 因此接口不是特殊的抽象类
接口的回调:用接口的引用型变量 接收 实现接口的类的对象
例如:DaoInterface daoInterface=new Daompl();
接口是功能规范,便于维护,下降耦合性
多个无关的类能够实现同一个接口
一个类能够实现多个无关的接口
instanceOf造型的时候使用,判断对象类型是否符合造型要求
内部类:一个类定义在一个类的内部,分为实例内部类和方法内部类,不能多用,
内部类和外部类的关系是组成关系。
实例内部类的特色:
命名空间只在外部类中的方法能够识别,若是外部类外部的方法须要使用的话 ,须要使用调用外部类.内部类来使用
类中的内部类能够访问外部类的私有属性
建立内部类对象,必须先有外部类对象
内部类会自动拥有外部类对象的引用
私有内部类只能在包含此内部类的外部类实例方法中被建立,私有内部类省略名称成为匿名内部类。
局部内部类使用的参数是final类型,也会自动拥有对外部类对象的引用
Inner class 能够声明为 static private ,若是是静态内部类就不能再访问外部类的非静态属性。
异常:
使用异常目的:
1,因为资源缘由形成程序出错,预先用异常进行处理(IOException)编译检查此类异常
2,对于运行时异常,经过异常机制找到异常缘由而且给予解决
持久层不处理异常,业务层不处理异常,通常都在测试层处理异常
异常的种类:
Error:AWTError / LinkageError
Throwabel
Exception:IOException/……/RuntimeException
异常的数据结构:
e.getMessage();公有的获取异常信息的方法
e.toString();调用e.getMessage(),而且显示异常对象的类型
e.PrintStrackTrace();异常栈跟踪,调用e.toString(),而且输出发生异常的代码位置
一个try{}后面能够接多个catch()成正金字塔形式,最后catch (Exception e)
拦截异常后要进行处理
倘若finally 中有 return:
返回值栈,会覆盖正常流程中的return值
会隐藏异常流程中的异常结果,还会隐藏异常
finally中通常最好不要有return值
自定义异常:
自定义异常类继承Exception,定义两个构造方法,一个无参的,一个有参数的构造方法。
public MyException(String msg){ super(msg); }
Property在java util.*;包下面
Property 中用空格,冒号区分 name 和value;
用setProperty()方法修改property对象中的值
用getProperty()方法获取property对象中的值
load();//用于加载property文件
store();//用于保存修改后的property文件
明日讲课内容:
Math
String
Collection
文件过滤
1.3版本:
使用线程同步,同一时刻只能使用一个线程
采用工厂模式完成业务层和持久层操做
业务层和持久层之间加了工厂
类锁的机制(静态锁):用反射对象的锁
业务层:设计单例时也加上静态锁。
1.4版本
awt 界面
1 Math类
1.1 final类型,构造方法私有。全部使用的方法都是静态的,由类调用。
1.2 提供两个static final 类型的实例全局量 PI(圆周率)和E(天然对数)
1.3 方法
1.3.1 ceil (返回大于或等于参数的最小整数)
1.3.2 floor (返回小于或等于参数的最大整数)
1.3.3 round(返回四舍五入的整数值)
1.3.4 变量的取值:max,min,abs(绝对值)
1.3.5 对数指数:log,exp
1.3.6 平方根 sqrt,幂运算pow,random 随机数,
1.3.7 常量 PI,E
1.3.8 sin cos acos atan tan asin (里面的参数是弧度,double类型的数值),toDegrees():转化为角度 toRadians();//转换为弧度
2 字符串类
2.1 String类,final类型,不能被继承,实现了序列化接口,比较器的接口,排序接口,能够进行存储,比较,排序
2.2 String内部是final类型的字符数组对象,一旦建立不能被修改,只能建立新的字符串对象
2.3 String对象表明一组不可改变的Unicode字符序列 private final char value[],任何试图改变string对象的方法都会建立一个新的字符串对象
2.4 String对象的建立
2.4.1 String str1=”abc”;//在方法区的常量池,能够共享
2.4.2 经过new String对象
2.4.2.1 String str=new String(“abc”);//会建立两个对象,一个在方法区的常量池,一个在堆里面
2.4.2.2 String(char[] value);//按字符数组建立字符串对象
2.4.2.3 String(byte[] value);//按字节数组建立字符串对象
2.4.2.4 String(byte[] value,String charsetName);//根据charsetName指定的字符编码,按字节数组参数建立字符串对象
2.5 String类的方法
2.5.1 concat:字符串的附加,相似 链接+,新串在方法区中
2.5.2 s1+=s2;//s1,s2都存在的状况下,建立两个字符串对象,一个在堆中,一个在方法区
2.5.3 replace ,repalcaeAll:字符串的替换
2.4.2.1 str.replaceAll(“hello”,”dfx”);//把全部的hello换成dfx
2.5.4 subString:求子串
2.3.4.1 subString(1,9);//取第一个位置包括第一个,到第9-1个位置的子串
2.3.4.2 subString(1);//取从第一个位置开始之后的全部字符
2.3.5 toLowerCase:转换为小写
2.3.6 toUpperCase:转换为大写
2.4 查找字符的方法
2.4.4 endsWith:尾部匹配
2.4.4.1 str.endsWith(“.java”);//判断末尾的字符串是否匹配 匹配返回true
2.4.5 startsWith:头部匹配//返回boolean类型
2.4.6 indexOf:找出索引位置
2.4.6.1: str.indexOf(“a”,2);//从第二字符起,a首次出现的位置
2.4.7 lastIndexOf:
2.4.7.1:str.lastIndexOf(“a”,2);//从第二个位置开始反向找a首次出现的位置(反向搜索)
2.4.7.1 str.lastIndexOf(“a”);//从第0个位置开始反向搜索,没有 返回-1
2.4.8 split :分隔
2.4.8.1 str.split(“,”);按逗号分割后用String[] 接收,分隔为多个字符串
2.4.9 trim:首位空格删除
2.4.10 charAt;找到字符串出现的位置
2.4.11 String方法的实例
String str=”123”; String str1=”123”; //生成一个对象,在方法区的常量池中建立
String str2=new String(“aa”);//生成两个String对象,堆中一个方法区一个
String str3=new String(“vv”); String str4=new String(“vv”);//建立三个 两个在堆中,一个在方法区的常量池中
str+=str1;//建立一个新的字符串对象,链接后的新字符串在堆中开辟空间
String s=new String(“hello”);
String s1=”world”;
s+=s1;
System.out.println(s==”helloWorld”);//结果为false
用追加(+)或者是链接(contact)建立的新串,在常量池中有一份,在堆中也有一份。比较的是堆中的那个对象。
2.4.12 StringBuffer:
构造方法 public StringBuffer(){super(16);}//自动增长16个缓冲空间
Stringbuffer具备必定的缓存,缓存容量是能够增长的
StringBuilder是线程安全的,使用缓存时不会建立新的对象
Stringbuffer和 String比较:
都用来处理字符串
都提供 了length() charAt() subString()
StringBuffer类对象可变,改变其缓冲区不会建立新的对象
StringBuffer没有复写equals方法,不支持+运算
stringBuffer覆盖了toString(),可是 和String的方法实现不同
String中追加必定会建立新的String对象,StringBuffer中追加不会建立新的对象,追加之后的对象就是原来被追加的对象。
StringBuffer和String不是同一种类型,不能比较。
StringBuffer 使用toString()方法后,会建立String类型的对象,把stringBuffer里面的字符串赋值给String类型的对象,返回新的String类型对象的地址。新的String对象再调用string类型的toString()显示输出字符串。
String和StringBuffer的使用场合:
StringBuffer sb=new StringBuffer(“as”);//建立两个对象
StringBuffer更节省内存空间
字符串常常变换的场合用StringBuffer
StringBuffer的容量为20,若是追加200的数据,也不会建立新的StringBuffer对象,只会扩大缓存空间,不会建立新的对象。
如何优化StringBuffer?(如何优化字符串管理?)
预先估算缓存容量,提升stringBuffer的执行效率。String 和 StringBuffer内部都是char[] 数组,最大的缺点是长度固定。
2.4.13 StringBuilder:
StringBuffer和StringBuilder比较
都具备缓存功能
StringBuffer线程安全,一个线程使用不会影响别的线程使用信息
StringBuilder线程不安全(能够人为加锁,保证安全 )
1 文件操做
File 在 java.io.*;下面
建立文件对象:
File file=new File(“a.txt”);//在相对路劲下建立文件
File file1=new File(“Mydos”,”a.txt”);//指定文件所在的目录
2 Deprecation
javac –deprecation A.java;//用来编译过时的文件类 表示已通过期了 发出警告
File 类的方法
getName();//获取文件或者目录的名字
getPath();//获取文件或者目录的路径
getAbsolutePath();//获取文件或者目录的绝对路径
getParent();//获取文件或者目录的根路径
boolean renameTo(File newName);//更名
boolean exist();//是否存在
boolean canWrite();//是否可写
boolean isDireactory();//是不是目录
String[] list();//把路径下的全部文件遍历输出
File currDir=new File(“f://abc”);//找到指定目录
if(currDir.isDirecory){//判断是否为目录
String[] files= currDir.list();//将目录用String[] 对象接收
}
for(String file1:files){//循环输出全部目录
System.out.println(“file:”+file1);
}
文件的过滤:JavaFilter implements FilenameFilter接口,须要实现accpet()方法。
public boolean accpet(File dir,String name){
File f=new File(dir,name);
if(f.isDirectory()){
return true;
}else {
retrun name.endsWith(“.java”);
}
}
String[] files= currDir.list(new JavaFilter());//将经过过滤的目录用String[] 对象接收
自动调用accept()的叫回调
accept的实现叫搜索策略
递归搜索:(思想)
先按顺序搜索,找到目录时,直接进去目录下搜索,再按顺序进行搜索,若是目录中存在目录则依旧再次进入目录搜索。以此类推,最后一个目录结构搜索结束后再处理别的文件依次从最后一层倒过来搜索。(搜索到目录时就进入目录搜索知道没有目录了再跳出来一次搜索)
做业:1.手工实现回调和策略搜索
2.多目录文件查找
做业1:
import java.io.File;
/**
* 手工实现一级文件搜索
* 找出全部的前缀名为String的文件
* @author DFX 2017/07/12
* */
public class FileSearchOne {
File currDir=new File("F:\\Users\\javaBase\\src\\string");//建立目录文件夹
public static void main(String[] args) {
FileSearchOne fso=new FileSearchOne();//建立当前对象
fso.fileList();//调用列出符合过滤条件的文件或目录名的方法
}
public void fileList(){//列出文件的方法
if(currDir.isDirectory()){//判断当前文件是否为目录
String[] javaFiles=currDir.list(new JavaFilter());//用字符串接收当前符合过滤条件的文件
for(int i=0;i<javaFiles.length;i++){//列出当前目录下符合过滤条件的全部文件,包含隐藏文件
System.out.println(javaFiles[i]);//输出文件或者目录名称
}
}
}
}
import java.io.File;
import java.io.FilenameFilter;
/**
* 文件过滤类
* 实现FilenameFilter接口,覆盖accpet()方法
* @author DFX 2017/07/12
* */
public class JavaFilter implements FilenameFilter{
public JavaFilter(){}
@Override
public boolean accept(File dir, String name) {//dir:指文件目录,name:文件名
File f=new File(dir,name);
if(f.isDirectory()){//判断是否为目录结构
return true;//为目录结构时返回目录
}else{
return name.startsWith("String");//返回以String开头的文件
}
}
}
做业二:
import java.io.File;
/***
* 递归搜索指定过滤文件
* @Author DFX 2017/07/12
*
* */
public class FileSearchMore {
/**
* @param args
*/
public static void main(String[] args) {
FileSearchMore fsc=new FileSearchMore();
File dir=new File("F:\\Users");
fsc.showDir(dir);
}
//函数调用本身 称为递归
public void showDir(File currDir){
File[] files=currDir.listFiles(new JavaFilterMore());//列出当前目录下的全部文件
for(int x=0;x<files.length;x++){
if(files[x].isDirectory()){
showDir(files[x]);//是目录的时候就递归,
}else{
System.out.println(files[x]);//不是目录就不用递归,直接输出
}
}
}
}
import java.io.File;
import java.io.FilenameFilter;
/**
* 多个层件目录搜索过滤类
* @author DFX 2017/07/12
*
* */
public class JavaFilterMore implements FilenameFilter {
@Override
public boolean accept(File dir, String name) {
File f=new File(dir,name);
if(f.isDirectory()){
return true;
}else{
return name.endsWith(".java");//返回以.txt结尾的文件
}
}
}
集合和数组:
相同点:都是存放数据的容器
不一样点:
1, 数组经过类建立数组对象,集合经过接口实现类建立对象(更好维护)
2,一旦数组建立对象了长度固定,集合长度可变(空数组无心义,空集合有意义)
3,数组能够放基本类型的数据也能够放引用类型的数据,集合只能存放对象的地址(引用类型的数据)
4,数组定义了元素类型必须保持一致,集合引用类型的数据能够不同(集合存在造型问题)
5,原则上数组存放的元素是有序可重复的,集合除了(List)都是无序不可重复存储的
6,数组经过下标取得元素,集合通常经过迭代取元素(list能够不经过迭代)
7,数组没有复写toString(),集合复写了toString();(集合还复写了equals()和hashCode())
8, 数组的长度用length(),集合的长度用size();
9,集合的空间是能够删除的(remove),数组只能删掉某个空间的元素
10,原则上数组类是不能被复写的,可是集合能够复写(Hibernate复写了set集合增长了 懒加载功能)
Collections 存储数据的容器:集合数组对象变量
1 Collection:都有add和remove方法 都用Iterator迭代元素
1.1 Set 无序,不可重复,复写了equals hashCode toString,遍历用Iterator,也可使用加强for输出集合中的元素
1.1.1 hashSet:散列表 经过一维数组+单链表
1.2 List有序:是一个一维数组,有序可重复,能够经过下标遍历也能够经过Iterator遍历
1.2.1 ArrayList:线程不安全,高效
1.2.2 Vector:线程安全,效率低
1.2.2.1:Strack
2 Map:键值对存储,没有继承collection 没有Iterator方法,输出map中的元素对象须要借助于List ,Set 集合。 Key 和 Value 加在一块儿叫 Entry
2.1 HashMap:遍历HashMap中的全部元素, 用KeySet 把Map中的Key放入set集合,还有一种EntrySet,
2.2 HashTable
2.2.1 Properties:Key 和 Value为String类型
3 Iterator:线程不安全,效率高,都有自身的迭代功能 hasNext() next(),做用:方便的遍历list set集合中的元素
4 Enumeration:线程安全,效率低
5 使用集合必定要导入import java.util.*;包
集合通常经过接口实现类来建立
List 有序可重复
List list=new ArrayList();//list集合内部是一个可变长的一维数组
数组变长是指在建立一个新的集合数组
往集合中添加数据
list.add(1); //自动装箱和拆箱 Integer 类型
list.add(“as”);//String类型
list.add(new Integer(1));//Integer类型
list.add(newe Float(5.0f));//Float类型
集合复写了equals(),比较时 调用equals方法,
list.size();//集合长度
list.remove(“as”);//移除集合中的 as 元素
System.out.println(list);// 复写了toString() 输出集合中的全部元素,输出顺序和添加时一致
Set 无序不重复
Set set=new HashSet();
set.size();//集合长度
set.add(“one”);//String 类型
set.add(4);//自动装箱 Integer
set.add(new Integer(4));//Integer
Iterator it=set.iterator();//Iterator对象不能经过new来建立,只能经过方法建立。
While(it.hasNext()){//Iterator自身迭代输出set集合中的元素输出的元素类型为Object类型,输出的时候会自动调用toString方法,须要使用的时候须要人为造型
System.out.println(it.next());
}
Set集合中的元素不能经过下标来取元素,由于它是无序的,只能经过遍历取元素
Iterator是一个集合,不是迭代器,线程不安全效率高
Enumeration 是集合,线程安全效率低
Set集合的数据结构:一个线性数组+一个链表
Set集合的存储特色?(先hashCode再 equals)
往set集合中add元素:先经过hashCode()方法计算一维数组下标位置(哈希值),此位置不存在数值的话则直接添加,位置已经有元素了就把已存在的元素和新元素作equals比较,equals比较相同则用新的替换旧的,不一样则经过链表找到下一位置放入元素。每一个一维数组中的桶的哈希值是同样的,可是key不一样。
|
查找元素时,先作HashCode()比较,相同再作equals比较。
|
equals比较相同,hashCode必定相同。
|
|||||
一维数组每一个元素的位置叫作桶,桶中存放链表
元素的个数叫作容量 7
Size是指每一个位置上实际元素的个数
什么叫容量?全部的一维数组的个数叫容量(默认容量 16),数组长度为16
什么叫负载因子?size除以容量叫负载因子(默认 0.75)负载因子=size/capacity,负载因子越小,碰撞率越低,查找和删除效率越高。
Map 无序不可重复(key),Map的key 和value都是Object类型,除了Properties中的key 和 value是String 类型
Map map=new HashMap();
map.put(“1”,”mon”);//往map中设数值,分别是key和 value, key不能重复,重复时会覆盖,后面的那个value被保存
map.get(“1”);//取出map集合中key为1 的value值
System.out.println(map);//复写了toString(),把key 和value用等号链接输出 [1=mon]
map.remove(“1”);//移除key为1 的元素
遍历map中的元素
方法1:
Set set=map.keySet();//建立set集合,把map中的key设置到set集合中
Iterator it=set.iterator();//把set集合中存放的key放到iterator中进行迭代
While(it.hasNext()){
String key=(String)it.next();//获得key(通常是Object类型,因此须要转型)
String value=(String)map.get(key);//获得value
}
方法2:
Set set1=map.entrySet();
Iterator it1=set1.iterator();//把set集合中存放的key放到iterator中进行迭代
While(it1.hasNext()){
Map.Entry entry=(Map.Entry)it.next();//获得entry
entry.getKey();//经过entry获得key
entry.getValue();//经过entry获得value
}
Map的数据结构是key 和value的键值对
做业:经过map实现饱汉式单例,经过key找到类对象
import java.util.HashMap;
import java.util.Map;
/**
* Map实现 单例模式
* 比饱汉模式和饥汉模式更直接
* */
public class SingleTonMap {
public static Map map=new HashMap();//建立map集合
private SingleTonMap(){}
public static synchronized SingleTonMap getInstance(String key){//经过map集合的能够获得value ---单例对象
SingleTonMap value=(SingleTonMap)map.get(key);
if(value==null){//判断value是否为null
value=new SingleTonMap();//给value赋值
map.put(key, value);//将key和value设置到map中
}
return (SingleTonMap)map.get(key);//获得value 单例对象
}
}
测试类:
public class TestSingleTonMap {
/**
* 主测试类
* @param args
*/
public static void main(String[] args) {
SingleTonMap stm=SingleTonMap.getInstance("new SingleTonMap()");
SingleTonMap stm1=SingleTonMap.getInstance("new SingleTonMap()");
System.out.println(stm+"---"+stm1);//返回对象的地址
System.out.println(stm==stm1);//true
}
}
集合的扩充:
Collection 是一个接口,有几个子接口 list set
List 接口底下的类:
ArrayList:底层是数组,查找很快,删除和修改慢
LinkedList:内部是双向循环链表,既有前驱也有后继,插入删除特别快,查找比较慢
Vector:底层和arrayList同样,效率低,线程安全
Set接口底下的类
HashSet :数组加链表
SortedSet:实现了Comparable接口 ,无序不能够重复,可是能够按照key进行排序
TreeSet是sortedSet的子类
Map:
HashMap 的查找和删除都依赖于hashCode 和 equals
HashTable:数据结构和hashMap相似 散列表(哈希表),线程安全,效率低
Properties:数据结构和map同样,散列表。Key 和value都是String类型
程序:一段静态代码,程序执行的蓝本(代码,代码不占用资源,资源是指内存)
进程:程序的一次动态执行过程,从代码加载,执行到执行完毕的一个完整过程,做为蓝本的程序能够被屡次加载到系统的不一样的内存区域分别执行,分为不一样的进程。同一个程序它的进程不同。(进程须要资源,可是不一样的进程不会争用资源,进程能够同时进行,互不影响)
线程:进程内部单一的一个顺序控制流。一个进程执行过程当中能够产生多个线程,每一个线程也有本身的产生,存在和消失的过程。(一个进程的多个线程,线程之间争用资源和空间)
线程是为多个用户服务的独立线索。
线程类必须复写run()方法,JVM执行程序,主线程先建立,
public class Machine extends Thread{
public void run(){
for(int i=0;i<10;i++){
System.out.println(currentThread().getName()+”--”+a);
//currentThread()是指获得当前线程的地址(线程的引用)
//currentThread().getName();指获得当前的线程名
}
sleep();//静态方法
try{}catch(InterruptedException e){}
}
public static void main(String[] args){
Machine mc=new Machine();//建立一个线程对象
mc.setName(“m1”);//将线程命名为m1
mc.setPriority(“Thread.MAX_PRIORITY”);
mc.start();//使得mc处于就绪状态,就绪状态的线程特色,已经被分配了指令计数器,已经分配了工做空间 --栈
mc.run();//主线程执行mc线程的run方法,m1线程的入口方法
}
}
线程依赖于底层,调度策略不惟一。调度策略混乱,因此每次执行结果不惟一。
按线程分栈,每一个线程对应一个栈(相互独立),每一个栈中有多个方法。
处于死亡状态的线程特色:释放栈里面的工做空间,被GC回收
线程命名优先级和名字应该在线程就绪状态以前设定。
线程生命周期状态转换图:
线程的生命周期:
线程的建立状态:
Jvm一启动就建立主线程
普通线程在主线程中建立(在堆里建立空间 new 线程对象)
主线程里建立的线程和主线程具备相同的优先级,激活了start,就会和主线程抢占资源。
Start是激活线程
线程的就绪状态:
主线程执行某个线程的start ,线程就被激活,能够和主线程抢占资源。就绪状态线程的特色:已经分配了资源处理机的指令计数器(PC),已经被分配了栈工做空间
线程的运行状态:
虚拟机从就绪状态中选择一个线程占用处理机,这种选择就绪线程占用处理机的方式叫作调度策略。run()方法是除了主线程之外,其它线程的入口。特色:占用CPU执行程序。
线程的阻塞状态:
等待CPU,还不能释放资源,pc记录方法执行的指令,把栈桢的使用空间放在计数器里面。(计数器比较快),阻塞不能直接进入运行状态,要先进入到就绪态,等待运行。
线程的死亡状态:
内存空间被GC回收
1 线程:
线程的工做空间是稳定的,除非线程死亡
线程的方法的工做空间是不稳定的,执行完后就会被GC回收
处于就绪状态的线程能够有多个,可是处于执行状态的线程只有一个
强行唤醒睡眠中的线程会使得线程处于异常状态
线程睡眠时会进入阻塞状态,这时候就绪状态的线程会根据调度策略来进入执行状态。Java的调度策略是抢占式的策略。(随机调度策略)
C语言的调度策略是时间片轮转,先来先服务
栈中存放形参,局部变量,断点,临时数据
死亡状态的线程释放资源
处于阻塞态资源保存在PC和寄存器中
线程能够从运行态直接转到就绪态
主线程死亡的状态是主方法执行完,其它线程的死亡状态是其run方法执行完
线程的优先级:
Thread.MIN _PRIORITY=1;
Thread.NORM _PRIORITY=5;//主方法的线程优先级为5,普通线程没有设定优先级默认和主线程同样 均为5级
Thread.MAX _PRIORITY=10;
主线程是第五级,也能够经过SetPriority()方法设定优先级
yield()//只给同一优先级的线程让步,
抢占的时候 低优先级的给高优先级的让步
setDaemon(true);//将线程设为后台线程,而且启动(也叫守护线程)
后台线程的特色:由主线程建立,前台线程执行完了 ,后台线程自动结束(死亡)
Join的特色:当A线程执行到B线程的join方法时,A线程就会等待,一直等到B线程执行完,A才会执行。Join用来临时加入线程执行。
前台线程和后台线程的调度机制就是时间片轮起色制
主线程死亡后,后台线程在分配的时间内会继续执行,时间到了就会自动销毁
若是调度机制是时间片轮起色制,yeild()方法不会对线程的执行顺序形成影响
主线程执行完主方法建立线程对象后会死亡,可是不影响其建立的程的执行
让多个线程共享同一个资源,须要在内部类中建立线程
建立线程的方法
1.1 继承Thread类,实现run()方法
1.2 实现Runnable接口,实现run()方法 建立的类不是线程类,对象也不是线程对象。把接口建立的对象做为参数方法Thread 对象建立中才是线程类。这个类的对象是为了线程类提供run()方法。
例如:
MyThread mt=new MyThread();//MyThread类实现了Runnable接口,而且实现了run()方法
Thread thread=new Thread(mt);//thread才是线程对象,调用有参构造方法,参数必定是对象的地址,而且所指的对象必定要实现Runnable接口,实现run()方法。
实现资源共享时,Thread thread1=new Thread(mt);
Thread thread2=new Thread(mt);
thread,thread1,thread2共享mt所指对象的变量。
1.3 线程的建立,实现Runnable接口,能够不用建立内部类实现资源共享。
1.4 isAlive();//判断线程对象是否处于激活状态
1.5 终止线程的方法
1.5.1 经过设定共享数据,根据标记控制线程执行。共享相同对象的变量,修改变量的属性值。
1.5.2 thread.stop();//在时间片范围内直接终止thread线程,此方法不推荐使用,若是thread线程正在执行原子操做,忽然终止会破坏数据的原子性,影响对其余线程的使用。
1.5.3 thread.interrupt();//thread在睡眠时,主线程执行thread.interrupt(),主线程强行终止thread线程的睡眠,让thread线程处于就绪状态,一旦thread被唤醒后,thread线程从(catch)异常代码开始执行,抛出异常,终止线程
2 线程的同步
Synchronized:同步能够保证数据的原子性不被破坏
不一样的线程对象执行的run方法在不一样的工做空间
锁是一种对临界资源控制的机制,利用每一个对象自身的功能。
Synchronized(obj){};//对象锁,控制语句块
对实例方法加锁时,锁的是调用实例方法的对象。传递的锁对象是 this
对象锁:主要锁语句块(同步块)做用范围为上锁的语句块
方法锁:锁的是调用该方法的对象的全部方法(实例方法)做用范围是对象的全部方法
类锁:锁的是加载类时建立的反射对象。静态方法经过类调用,加载类会建立和类相关的反射对象,给静态方法加锁时,锁的是全部类上的静态方法。一个线程访问一个静态方法,全部线程和全部静态方法都不能被执行。做用范围是该类的全部静态方法 传递的锁对象是 类名.class
做业:
使用内部类建立四个线程,两个对实例全局变量i作+1操做,两个线程对i作-1操做。加减操做不用考虑顺序。
1 添加sleep() 能够人为的控制调度策略,更改线程的执行顺序
线程对象都具备start()方法,若是不能调用start()方法,则不是线程对象
普通线程的run()方法执行完后,线程死亡,内存被GC回收。
锁体如今哪?
对象就是锁。synchronized(new Object());
synchronized的做用?
锁语句块,保证同一时刻只有一个线程能够操做这段语句块。只能操做结束后其它线程才能操做。
上锁的条件:至少有两个或两个以上的线程。
无论是对象锁仍是类锁或者是方法锁,起做用的都是对象。
实例方法锁:锁对象是this,一旦调用一个方法,其它线程没法使用该类对象的 其它方法。
2 同步代码块设置不当会致使程序出错
This.notify();//(唤醒等待池中的线程,放到锁池里),保证生产者和消费者不会争用资源(此状态下当前线程依旧占领处理机,当执行到wait方法时才让出处理机,本身进入等待池中)
this.wait();//开启锁,让别的线程执行,当前线程进入等待池。
3 生产者和消费者
进入锁池表示进入阻塞态
Wait():先把锁池开启,把本身放入等待池中等待
生产者送情报,送完以后要等消费者取到情报后才能离开
notify():把等待池中的线程放到锁池中,这时候处理机依旧是当前线程在占领,直到当前线程执行wait()方法,被唤醒的线程才会开始占领处理机执行程序。
消费者先回来的·
4 线程如何保证安全性:synchronized
线程如何保证并发性:ThreadLocal
线程出现死锁:方法锁中的有语句块锁,语句块锁中有方法锁,锁的对象不一样,一个是this,一个是obj。wait(),使得线程处于等待池;notify(),唤醒的线程是按顺序唤醒的,通常是唤醒第一个进入等待池中等待的线程。线程进入等待池是按顺序进入的,先进入的通常会先被唤醒。
notifyAll():唤醒线程池中全部处于等待的线程。
等待和唤醒必须是同一个锁,锁能够是任意对象,能够被任意对象调用的方法定义在Object类中。
非线程资源类中也能够有同步资源,同步代码块。
/**
* 用内部类实现线程,建立四个线程,
* 其中两个线程对实例全局变量+1操做,两个线程对实例全局变量-1操做。
* 加减不考虑前后顺序
* */
public class TestThread {
int i=10;//目标操做数
// int count=0,count1=0;//用来控制执行次数的标记,当count>10的时候就结束
// Object obj=new Object();
/**
* @param args
*/
public static void main(String[] args) {
TestThread tt=new TestThread();//建立当前类的外部类对象,用于建立内部类
AddThread addThread=tt.new AddThread();//建立内部类对象
SubstractThread subThread=tt.new SubstractThread();//建立内部类对象
Thread threadAdd=new Thread(addThread);//建立作+1操做的线程对象
Thread threadAdd1=new Thread(addThread);
Thread threadSub=new Thread(subThread);//建立作-1操做的线程对象
Thread threadSub1=new Thread(subThread);
threadAdd.start();//启动线程,使得线程处于就绪状态
threadAdd1.start();
threadSub.start();
threadSub1.start();
}
private synchronized void inc(){//同步这两个方法,使得线程不能同时对i进行+1 和-1操做,只能选择其中一个操做。
i++;
}
private synchronized void dec(){
i--;
}
//作+1操做的内部类
class AddThread implements Runnable{
public void run(){
for(int k=0;k<5;k++){
//打印出当前执行的线程名 和当前i的值
synchronized(obj){ System.out.println(Thread.currentThread().getName()+"--add---前:i= "+i);
inc();
System.out.println(Thread.currentThread().getName()+"--add---后:i= "+i);
}
}
}
}
//作-1操做的内部类
class SubstractThread implements Runnable{
public void run(){
for(int j=0;j<5;j++){
//打印出当前执行的线程名 和当前i的值
Synchronized(obj){
System.out.println(Thread.currentThread().getName()+"--substract---前:i= "+i);
dec();
System.out.println(Thread.currentThread().getName()+"--substract---后:i= "+i);
}
}
}
}
}
5 I/O流:java经过流完成了和外部数据的交互
外部数据是指外存,标准设备,网络
I/O流是一条用来传送数据的管道
5.1 输入流:读 从外向内,读入到内存的存储文件中
5.2 输出流:写 从内向外,输出到外部的文件中
5.3 流的传送单位是字节流 byte
5.4 从文件的角度看待流:
5.4.1:文本文件 显示器和键盘,是用一个字节来存放一个字符的,是可见的,显示器是典型的文本文件,从键盘中输入的都是字符,以后转换为二进制。 特色:以字符的形式出现,每一个字符占用一个字节, 文件文件都是可见的 文本文件最大的特色是须要转换
3.141592678:以文本文件存储占11个字节,存放的是ASIIC码值,最后显示的是字符
5.4.2:二进制文件 .exe文件,之内存的方法存储,double类型3.141592678 八个字节。二进制文件和内存的形式相同,不可见,不须要转换,二进制文件的读写效率更高
数据在内存中运算都是以二进制类型进行运算的
字节流的种类:
文件字节流:从文件中拿数据
标准字节流:从键盘缓冲区中拿数据
网络字节流:经过Socket从信道中拿数据
管道字节流:从管道中拿数据
顺序字节流:sequence流,通常只有一种顺序输入流,
全部字节流都有个共同的父类,也叫作基类。输入流的基类:InputStream (抽象类),输出流的基类:OutputStream(抽象类),这两个基类是抽象类,不是接口。
文件字节输入流和文件字节输出流:(会产生编译异常)
主要catch()两个异常,FileNotFoundException 和 IOException
FileInputStream:
FileInputStream:若是文件存在,会删除从新建立,不存在也不会抛出异常,会建立新的文件
System.out.println()和System.err.println()是同样的,能够一块儿使用
随机访问流:
RandomAccessFile:它的基类 (父类)是Object,随机流不区分输入流和输出流,能够随机访问文件当中的任何字符,随机流能够访问文本文件和二进制文件,对文件的访问方式要设定,
二进制文件的特色:存放数据的方式和内存同样
randf.seek(2*4);//将文件位置移动8个位置,每一个int类型的数据占4个字节
readInt();//按二进制文件读取数据,一次读取四个字节。
一、 文件字节流处理文本文件,对象流处理二进制文件
二、 字节流:是最基本的流
int c; while(c=fis.read()!=-1) fos.write(c);
对于输入流,必定要 fis.flush();
三、随机流 RandomAccessFile
RandomAccessFile raf=new RandomAccessFile(“a.txt”,”rw”);//随机流,指定文本和访问方式。
文件位置指针的移动位置是能够手动肯定的,以字节为单位
raf.seek(1*4);//指定指针开始查看的位置
四、套接流BufferedInputStream BufferedOutputStream
过滤流,缓冲流: BufferedInputStream bin=new BufferedInputStream(in,256);//in:表示文件,256表示一次最多读取字节或者字符的个数
byte[] buf=new byte[1024];
int c=bin.read(buf,0,512);//c返回的是实际读取到的字符的个数
流关闭时,能够直接只关闭套接流。
BufferedOutputStream : bos.write();以后必定要用bos.flush();来强制输出。
Buffered流的特色:
一、 要有字节流对象做为参数,也能够是对象流
二、 通常处理文本文件,不处理二进制文件
三、 通常来讲不能一次读取一行字符
四、 做为套接流,而且区分输入流和输出流
Data流(数据流)
一、是一种嵌入流,首先得有字节流(文件字节流,网络字节流,通常不用标准字节流)
二、既能够读取文本文件,又能够像随机流同样存取二进制文件,并且可以按行读取(readLine())
三、若是嵌入到网络字节流,能够读取还能对网络字节流进行编码
DataInputStream
Dis.readUTF();
Dis.writeUTF();
Data流处理二进制文件:必定要按存的顺序去读取文件,否则可能会乱码
Data流的readLine()读取的必定是文本文件,
通信的双工理论:只能听见对方的不能听见本身的声音。
文件流的目标是文件,网络流的目标是网络信道
标准流: 通常套接buffered流,通常不套接Data流
键盘和显示器都是字节设备
标准字节输入流(InputStream)的最大功能是 从键盘中拿到的字节数据,转换成字符串 System.in
标准字节输出流(PrintStream)从文本中拿到数据到显示器中显示 System.out/System.err
System类不能同时继承InputStream和PrintStream这两个类,因此System中须要调用到InputStream和PrintStrem 的方法是静态方法,将InputStream 和 PrintStream做为参数传入方法中。
对象流:
可以输入输出对象的流称为对象流
对象的持续性:可以记录本身的状态以便未来再生的能力,叫作对象的持续性
对象的串行化(序列化):对象传送本身状态的过程叫作串行化
从流中拿出对象的状态生成对象的过程又叫反序列化,反正串行化
怎么完成串行化?
一、 生成对象的类必定要加入串行化协议(对象类 implements Serializable接口,不用实现任何方法 )
二、 对对象的属性赋予状态,对对象属性赋值 (建立类对象,而且给对象的实例全局变量赋值)
三、 建立对象输出流对象,调用相应的方法 writeObject();(FileOutputStream )
四、 把对象所指的状态经过管道一步一步的写到对象输出流所指定的二进制文件中
存放对象状态的文件只能是二进制文件
对象的状态想要传送,对象类必须实现Serializable
对象输入流对象:ObjectInputStream
ObjectInputStream ois=new ObjectInputStream(fin);
Student stu=(Student)ois.readObject();
对象输出流对象:ObjectOutputStream
反序列化:经过对象输入流对象从指定位置读取对象的状态,调用 readObject(),将对象状态再生成对象
在变量前加上 transient表示不想进行传送,在进行网络传送时会不进行传送
对象的序列化:
//对象的序列化
public void objSer()throws IOException{
//建立须要被序列化的对象
Student stu1=new Student();
stu1.setNum(123);
stu1.setName("西欧爱心");
FileOutputStream fos=new FileOutputStream("1.txt");//建立字节文件输出流对象
ObjectOutputStream oos=new ObjectOutputStream(fos);//建立对象输出流对象
oos.writeObject(stu1);//序列化对象
oos.close();//关闭对象输出流
}
建立对象的五种方法:
一、 New//new Student();
二、 方法 //set.iterator();
三、 反射
in=new FileInputStream("hello.properties");
prop.load(in);//加载文件
String className=prop.getProperty("className");//获得配置文件中的类名
Class c=Class.forName(className);//反射类
ReflectDemo reflectDemo=(ReflectDemo)c.newInstance();//将反射类获得的实例对象造型为接口类型
四、 反序列化
//对象的反序列化
public void objRecov() throws IOException, ClassNotFoundException{
FileInputStream fis=new FileInputStream("1.txt");//建立字节文件输入流
ObjectInputStream ois=new ObjectInputStream(fis);//建立对象输入流对象
Student stu=(Student)ois.readObject();//对象的反序列化,经过反序列化获得对象
System.out.println(stu.getNum()+"--"+stu.getName());//使用反序列化获得的对象
ois.close();//关闭对象输入流
五、 克隆
管道流 PipedInputStream PipedOutputStream
特色:
一、 输入流和输出流首位相接
二、 文件内存把输出放在管道输出流(内到外),另外一个线程从管道中拿出数据到内存 称为管道输入流(外到内)
三、 管道流的传输不涉及文件也不涉及网络(都是字节流)
PipedInputStream pis=new PipedInputStream();//建立一个管道输入流对象
PipedOutputStream pos=new PipedOutputStream(pis);//建立一个管道输出流对象,将管道输入流对象做为参数传给管道输出流对象
pos.write((byte)123);//将字节123写入管道中
pis.read();//读取管道中的数据,若是管道中没有数据则会一直处于等待状态
管道流的做用通常是用于线程之间的数据传送,管道流必须依附线程
线程死亡后,管道流若是未关闭继续读取的话会报错: write and dead
生产者拿到管道输出流,消费者拿到管道输入流,将管道流做为建立线程对象的构造方法的参数传入。
管道流使用完后要记得关闭, pis.close();
顺序流:SequenceStream
FileInputStream fis=new FileInputStream(“file.txt”);
FileInputStream fis1=new FileInputStream(“file1.txt”);
SequenceInputStream sis=new SequenceInputStream(fis,fis1);//链接多个文件字节输入流
DataInputStream dis=new DataInputStream(sis);//将顺序流方法数据流中 以行为单位读取
String str=dis.readLine();//(判断结束的比较对象为 null)
字符流:一次只能读取一个字节
字符流的基类为Reader 和 Writer
InputStreamReader dis=new InputStreamReader(new FileInputStream(“file.txt”));
字符流基于字节流,建立字符流对象时,要把字节流对象做为参数传入。
字符BufferedReader 一次能够读取一行 readLine()
三种套接流:(用来套接字节流)
1)、Buffered流
2)、Data流
3)、Object流
反射:如何经过字符串拿到反射对象 完成自动装配
String className="package.className";//写出类名的全路径名
* Class c=class.forName(className);//加载反射类
* Object obj=c.newInstance();//建立反射类对象
* User user=(User)obj;//强转类型
* user.setName();//调用方法
*
* 反射的缺点:
* 效率低,打破对象的封装性,代码复杂,可维护性不是很好
*
* 优势:
* 能够直接访问对象的方法 属性
* 建立对象 能够反编译
*
* 通常状况下不要用反射
用反射的目的:用户的需求改变不用改变当前的代码,只须要改配置文件就能够了
做业:用管道流实现生产者消费者
package homework;
import java.io.IOException;
import java.io.PipedOutputStream;
/**
* 生产者类
* */
public class ProductorPipe implements Runnable {
private PipedOutputStream pipeOut;//定义管道流输出流用来传输数据
public ProductorPipe(PipedOutputStream pipeOut){//在构造方法中传入管道流输出流对象,使得建立生产者线程对象的时候注入管道流输出对象
this.pipeOut=pipeOut;
}
public void run(){
for(int i=0;i<10;i++){
try {
pipeOut.write((byte)i);//往管道流中写入数据
System.out.println("write---"+i);
} catch (IOException e) {
e.printStackTrace();
}
}
try {
pipeOut.close();//关闭输出管道流
} catch (IOException e) {
e.printStackTrace();
}
}
}
package homework;
import java.io.IOException;
import java.io.PipedInputStream;
/**
* 消费者类
* */
public class ConsumerPipe implements Runnable{
private PipedInputStream pipeIn;//定义管道输入流来读取管道中的数据
public ConsumerPipe(PipedInputStream pipeIn){//在构造方法中传入管道流输入流对象,使得建立消费者线程对象的时候注入管道流输入对象
this.pipeIn=pipeIn;
}
public void run(){
for(int i=0;i<30;i++){
try {
int j=(byte)pipeIn.read();//读取管道流中数据,当管道中没有数据的时候,会输出 -1
System.out.println("读数据---*****"+j);
} catch (IOException e) {
e.printStackTrace();
}
}
try {
pipeIn.close();//关闭管道输入流
} catch (IOException e) {
e.printStackTrace();
}
}
}
package homework;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
/**
* 测试管道流链接的生产者消费者线程
*
* */
public class TestPipeProCon {
public static void main(String[] args) {
PipedOutputStream pipeOut =new PipedOutputStream();//建立管道输出流对象
PipedInputStream pipeIn=null;
try {
pipeIn=new PipedInputStream(pipeOut);//建立管道输入流对象
} catch (IOException e) {
e.printStackTrace();
}
ProductorPipe pro=new ProductorPipe(pipeOut);//建立生产者对象
ConsumerPipe com=new ConsumerPipe(pipeIn);//建立消费者对象
Thread thPro=new Thread(pro);//建立生产者线程对象
Thread thCom=new Thread(com);//建立消费者线程对象
thPro.start();//启动生产者线程
thCom.start();//启动消费者线程
}
}
字符Buffered流能够按行读取,字节Buffered不能够按行读取。字符流不能读取二进制文件。
Data流能够按行读取也能够读取二进制文件
Awt:事件突发机制 观察者机制 (内部类/匿名类)
本周须要完成的项目:
计算器:菜单栏
银行项目1.4 :工厂模式 反射类
银行项目1.5 :awt
java聊天室:线程数组,线程集合
反射:如何经过字符串拿到反射对象 完成自动装配
String className="package.className";//写出类名的全路径名
* Class c=class.forName(className);//加载反射类
* Object obj=c.newInstance();//建立反射类对象
* User user=(User)obj;//强转类型
* user.setName();//调用方法
*
* 反射的缺点:
* 效率低,打破对象的封装性,代码复杂,可维护性不是很好
*
* 优势:
* 能够直接访问对象的方法 属性
* 建立对象 能够反编译
*
* 通常状况下不要用反射
动态装配:
一、 如何建立一个类型不断变化的对象?
二、 怎么用工厂完成装配?
Faotory 处于业务层和持久层之间,建立factory类的步骤:
一、 建立properties对象
二、 建立流对象 FileInputStream
三、 加载 load(),关闭流
四、 从properties文件中读取className的值(存储的类名要写全称 com.cx.UserDaoFactory),拿到的仅仅是字符串 类名 className
五、 加载到内存Class c= Class.forName(className);//建立映射对象,能够经过映射对象获得属性,方法。 映射对象能够经过getClass()获得。
六、 建立对象实例: Object obj=c.newInstance();
七、 造型 : userDao=(BankDaoInterface)obj;//按照接口造型,
八、 加同步的饱汉式单例获得当前类的对象
用反射的目的:用户的需求改变不用改变当前的代码,只须要改配置文件就能够了
1 工厂建立对象是单例模式,在项目当中只有一个工厂完成装配
2 工厂使用synchronized 保证安全性
工厂属于持久层
表示层:接受用户的请求,对请求进行分析
业务层:完成表示层所要求请求的功能
持久层:完成对数据库的存储操做
模型层:把数据封装到bean中 (bean:是数据在内存中的存储方式)
三、怎么使用工厂?
业务层接口上面对应的是表示层
业务层和持久层必须用接口
业务层也是单例模式 synchronized ,(一个请求多个线程来访问,使用单例保证一个请求建立一个业务对象,保证访问的安全性 <单例+同步>)
业务层使用<单例+同步>来建立业务对象是有必要的
安全级别越低,并发性越高
四、表示层怎么获取业务对象操做持久层?
业务层有持久层接口变量,工厂也有持久层接口变量
在建立业务层对象的时候,会调用业务层无参的构造方法,因此在业务层的构造方法中,建立工厂,经过建立工厂拿到持久层对象
业务层和工厂都使用<单例+同步>建立对象,持久层能够不用同步,保持单例就行
业务层经过工厂对象拿到工厂装配的持久层对象的地址,指定业务层该调用的持久层对象(体现了拥抱需求)
在业务层 经过工厂获得的持久层对象给业务层中定义的持久层实例全局变量赋值,而后在调用持久层中的方法
private ManagerImpl(){//业务层的构造方法
UserDaoFacory userDaoFactory= UserDaoFacory.getInastance();
UserDao= userDaoFactory.createUserDao();//createUserDao是工厂中的一个实例方法,用来返回经过反射获得的userDao对象方法
}
建立工厂作两件事:
一、 经过反射建立持久层对象(根据用户需求动态建立持久层对象)
二、 将持久对象装配给userDao(赋值给)(把持久层对象传给指定变量)
业务层:
一、在构造方法中建立工厂拿到工厂对象
二、拿到工厂对象中获得的(动态变化的)持久层对象
为何引用工厂模式?
持久层常常变化 ---- 拥抱需求
工厂被用了几回? (只用一次,完成装配)
只用一次,第一个线程被调度执行业务层对象的时候使用了工厂,业务对象只建立一次,因此也只调用了一次业务对象的构造方法,日后业务对象已存在,不用再建立。而且业务层已经肯定了该用哪一个持久层对象了,就不用再使用工厂了
在用工厂装配的时候,可不能够有多个线程完成装配操做?
不能够,工厂必须是<单例+同步>,保证安全性
工厂模式 链接业务层和表示层 做业
/**
* 工厂类<单例+同步>
* 经过反射从properties文件中获得持久层的实现类对象
* @Author DFX
* @Version 1.3 2017/07/18
* */
public class DaoFactory {
private DaoInterface daoImpl;//定义持久层接口实现类的对象
/*
* <饱汉式单例+同步>
*
* */
private static DaoFactory daoFactory=null;
private DaoFactory(){}
public synchronized static DaoFactory getInstance(){
if(daoFactory==null){
daoFactory=new DaoFactory();
}
return daoFactory;
}
/*
* 经过反射获得持久层实现类对象
* @Params null
* @Return DaoInterface
*
* */
public DaoInterface getObj(){
Properties prop=new Properties();
FileInputStream fis=null;
try {
fis=new FileInputStream("daoImpl.properties");
prop.load(fis);
String className=prop.getProperty("className");//获得反射类全名
Class c=Class.forName(className);//加载反射类
Object obj=c.newInstance();//建立反射类对象
daoImpl=(DaoInterface)obj;//对反射类对象造型为实例接口
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return daoImpl;//返回持久层实现类对象
}
}
在业务层的构造方法中经过工厂类获得持久层对象
DaoInterface daoImpl;
// 无参构造方法
public ManagerImpl() {
DaoFactory daoFactory=DaoFactory.getInstance();//获得工厂类对象
daoImpl=daoFactory.getObj();//经过工厂类对象获得持久层接口实现类对象
}
public static synchronized ManagerImpl getInstance(){};//静态锁,做用于和类所关联的反射对象
静态锁的目的:把线程的并行变成串行
业务层加锁->持久层加锁-> 数据库加锁->事务加锁(效率愈来愈高,安全性愈来愈低)
自我介绍:我的信息 本身所学的专业知识 应聘岗位技术
经常使用的容器 Frame 和 Panel
TextArea:文本域,一次能够写多行
TextField:文本区,一次只能够写一行
Panel 须要被加载到Frame中,panel 是不可见的//frame.add(panel);
TextField:文本
TextField(int columns):新建一个指定行数的文本域
布局:组件在框架中的排列方式
流式布局FlowLayout:从左到右,从上到下(根据框架大小自适应) 面板的默认布局
网格式布局 GridLayout: GridLayout(2,1);//指定 两行一列(计算器)
边界布局BorderLayout:是frame框架的默认布局,中间大,东南西北分
网格包布局GridBagLayout
Gridx=1;//X轴距离
Gridy=1;//Y轴距离
setHeight=1;//高度
setWidth=1;//宽度
Awt中没有单选框,只有Checkbox(复选框)
要设置单选框时,须要设定复选框组 CheckboxGroup
CheckboxGroup cg=new CheckboxGroup();
Checkbox cb=new Checkbox(female,cg,true);
选择框:
Choice movies=new Choices();//下拉列表框
Movies.addItem(“^^^”);
网格式布局
* public GridLayout(int rows,int cols,int hgap,int vgap)
* rows:行
* cols: 列
* hgap: 水平间距
* vgap: 垂直间距
*
* String str=but0.getLabel();//获得按钮上的内容
Awt的事件突发机制
组件会产生什么事件,监听器实现什么接口,有什么方法
1.一、 事件源产生事件,监听器处理事件。
1.二、 一个事件源可能会产生不一样类型的事件
1.三、 MyListener实现ActionListener接口,实现actionPerformed方法
1.四、 观察者模式:MyListener ml=new MyListener();//其中ml为观察者对象
1.五、 AddActionListener(new ActionListener(){//事件驱动
public void actionPerformed(ActionEvent e){
//这里写出须要的操做
}
});
1.六、 class ButAction extends Frame Implements ActionListener{//定义类时继承Frame框架实现ActionListener接口
public ButAction(){//构造方法中有this指针
but.addActionListener(this);//默认调用当前对象的actionPerformed方法
public void actionPerformed(ActionEvent e){//实现ActionListener接口中定义的方法
}
}
}
1.七、 ActionEvent:实现ActionListener接口,实现 actionPerformed方法
1.八、 ItemEvent:复选框,单选框,列表框的单击,选择框的单击会产生这个事件 实现 ItemListener接口 只有一个方法须要实现 itemStateChanged()
1.九、 FocusEvent(焦点事件):每一个组件都有这个事件,实现FocusListener接口,实现focusLost(焦点丢失) 和 focusGained(焦点得到)方法(适配器类:FocusAdapter) 焦点事件对数据的检查很是重要
tf.addFocusListener(new FocusAdapter(){//调用空实现类,能够只选择其中一个方法实现 ,还有个focusGained方法被空实现了
public void focusLost(FocusEvent e){//焦点丢失方法
TextField tf=(TextField)e.getSource();//拿到事件源
if(!tf.getText().equals(“Tom”)){//分析数据是否正确
tf.setText(“”);//清空文本框中的数据
tf.requestFocus();//从新得到焦点(光标的位置)
}
}
});
焦点事件能够对用户输入的信息作格式验证
1.十、 KeyEvent:键盘事件 。(能够对输入的任何字符作监听而且获取输入的字符)实现KeyListener接口,实现三个方法
keyPressed:键盘输入(按下)//显现键值①
int keCode=e.getKeyCode();//获得输入的字符
keyTyped:键盘按下并释放//显现键符②
e.getKeyChar();//获得键盘录入的字符
keyReleased :键盘释放(松开)
int keyCode=e.getKeyCode();
repaint();//重绘,让frame设置的属性当即显示效果
addKeyListener(new KeyAdapter(){
public void keyPressed(KeyEvent e){
}
});
1.十一、 MouseEvent:鼠标事件,有两种监听器 须要实现MouseListener或者 MouseMotionListener接口,接口中的方法有:
mouseClicked:单击 int clickNum=e.getClickCount();//获得鼠标单击次数(能够对文本框产生的事件作鼠标事件监听)
e.getX();//获得X坐标e.getY();//获得Y坐标
mouseEntered:
mouseExited:
mousePressed:
mouseReleased:
mouseDragged:
mouseMoved:
(适配器类:MouseAdapter)
1.十二、 适配器类:将监听器中的全部方法都实现,只是空实现。空实现的类叫作适配器类
1.1三、 WindowListener:窗口事件。能够继承WindowAdapter适配器类,此类已经对WindowListener接口中的全部方法都作了空实现。因此使用的时候能够选择本身须要用到的方法进行复写。
frame.addWindowListener(new WindowAdapter(){//窗体驱动
public void windowClosed(WindowEvent e){
System.exit(0);//退出,关闭窗体
}
});
1.1四、 多点监听器:
一个组件实现多个监听器接口,实现每一个接口中的每一个方法
一、 匿名内部类
将私有内部类,写到构造方法中,直接变成匿名内部类
在构造方法中:
this.addWindowListener(new WindowAdapter(){//这个对象没有类名,只知道这个对象的类继承了WindowAdapter父类
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
this.addWindowListener(new WindowListener(){//new后面跟一个接口,可是接口不能建立对象,这只能说明 这是个实现了WindowListener 接口的匿名类
});
匿名类的优势:代码简单
匿名类的缺点:可维护性差,不易理解,使用范围窄, 只能在一个场合使用
匿名类只在特殊场合使用:
一、 事件突发机制 作监听器
二、 Spring IOC 和AOP 的机制 callback 回调的核心技术
二、 Swing(Menu)用swing如何作菜单
Awt的缺点:
一、 依赖底层,在不一样的系统下显示的结果不一样
二、 没有单选框
三、 作出来的效果比较死板
四、 关闭时必定要使用事件突发机制
Swing:
Java 为swing提供JFC类库
使用swing要导入三个包 javax.swing.*; java.awt.*; java.awt.event.*;
Model:业务层 持久层 模型层
原则:作图形界面最好是不要把swing和awt混在一块儿写,不然会混乱 (由于swing是稳定的,awt是基于底层不稳定的)凡是以J开头的组件都属于swing,相似JFrame 。
JFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//自动实现窗口关闭
JButton.setMnemonic(KeyEvent.VK_F);//在按钮上设置快捷键 F
JButton上能够添加背景图片,再添加文字
JTextField jtxt=new JTextField(Document doc,int column,int row);
New JtextField(“默认文字”,”图片(ImageIcon)”,””);
JComboBox :组合框
菜单:
JMenuBar mb=new JMenuBar();//建立菜单条
f.setMenuBar(mb);//将菜单条放入框架中
JMenu m1=new JMenu(“文件”);//建立菜单
mb.add(m1);//把菜单添加到菜单条中
mb.setHelpMenu();//建立帮助菜单项
JMenuItem mi1=new JMenuItem(“新建”);//建立菜单项
m1.add(mi1);//将菜单项添加到菜单条上的菜单中
mi1.addActionListener();//菜单项能够添加事件监听事件
菜单项能够添加二级菜单(能够是普通菜单项,也能够是复选菜单项)
JCheckBoxMenuItem:复选菜单项
m1.add(“Hello World”);// 能够把字符串做为子菜单
m1.addSeparator();//在菜单中添加间隔线
菜单中添加菜单,表示被添加的菜单是二级菜单,以后再添加菜单项
1 通信协议:计算机域计算机之间通信的约定的方式
1.一、 OSI协议分为七层:物理层、链路层、网络层、传输层、会话层、表示层、应用层
1.二、 TCP/IP(传输控制/网际协议)参考模型包括五层:物理层、链路层、网络层、传输层、应用层(URL和URLConnection)
URLConnection:是对设备的链接
1.三、载波监听多路访问:先听后发,边听边发,碰撞后随机重发
1.四、 网络层:点到点
1.五、 传输层:端到端,不关心中间怎么传输(TCP和UDP协议)
1.六、UDP(用户数据报)协议特色:不可靠,无序,可是传送效率高
1.七、TCP(传输控制)协议特色:可靠,有序,以字节流的方式传送数据,一般被称为流通讯协议
1.八、端口号:标识网络应用的逻辑地址
1.8.一、 Oracle端口号:1521
sqlServer 端口号:1433
Mysql端口号:3306
1.8.二、端口号定义规范: 0~65535,其中0~1023为系统保留
2 Java提供的网络功能的四大类:
2.一、InetAddress:面向IP层,用于标识网络上的硬件资源(InetAddress:封装IP地址和端口信息) 网络层
2.1.一、构造方法私有化,不能用new来建立对象也不能用反射来建立。能够经过静态方法建立
2.1.二、域名:用来标识的字符串 例如:www.sina.com
2.1.三、静态方法:getLocalHost();//获取本机InetAddress对象
2.1.四、静态方法:InetAddress.getByName(“www.ztenc.com.cn”);//进入中兴服务器,经过域名找到服务器的IP地址和机器名
InetAddress address=InetAddress.getLocalHost();//获得主机名和主机的IP地址USER-20150330OI/172.16.0.126
System.out.println("address:"+address);
InetAddress host=InetAddress.getByName("USER-20150330OI");//根据主机名获得主机名和IP地址(USER-20150330OI/172.16.0.126)
System.out.println("host:"+host);
2.二、URLs:面向应用层,经过URL,标识网络服务器上的资源(URL和URLConnection)
2.三、Sockets:面向传输层。(Socket:客户端经过socket发送请求 ,ServerSocket:服务端经过ServerSocket对象作请求监听)
2.四、Datagram:DatagramPacket:数据报,DatagramSocket:邮递员 MulticastSocket:多波协议,发送方在指定端口上发送信息,发送端没有明确的地址,能够同时有多个接收方在指定端口上接收。(一我的发送多我的接收)
3 Applet类的字节码文件嵌入在html中,服务器经过下载字节码文件,运行程序
4 URL url=getCodeBase();//获得提供它的主机的URL实例,只在Applet程序中用
Host host=url.getHost();//利用URL获得主机名
InetAddress address=InetAddress.getByName(host);//根据主机名称获得主机名和主机的IP地址
DataSocket ds=new DataSocket();//邮递员
DatagramPacket dp= new DatagramPacket(buf,length,address,port);//buf:字节数组, length :一次传送数据的长度,address:主机的IP地址,port:服务器端口号
ds.send(dp);//邮递员发送数据报
5 URL url= new URL(“http://www.ztenv.com.cn/text.html”);//获得url(用于下载text.html文件)
经过URL(统一资源定位器)获取网络字节输入流对象,url.openStream(),返回一个网络输入字节流(从网络开始,读到客户端)
new InputStreamReader(url.openStream());//把字节流变成字符流
BufferedReader br=new BufferedReader(new InputStreamReader(url.openStream()));//把字符流套入buffer流
URL url=new URL(“file:/D:/a.txt”);//file协议,表示读取本机文件
6 URLConnection (用于上传文件)
URL url=new URL(“file:/D:/a.txt”);
URLConnection uc=url.openConnection();//获得链接对象
uc.getInputStream();//经过链接对象建立网络字节输入流对象,经过输入流读取数据,叫作下载
URL url1=new URL("file:/f:/Users/a.java");//file协议 读取本机文件
URLConnection uc=url1.openConnection();//获得链接对象
InputStreamReader in=new InputStreamReader(uc.getInputStream());//建立网络字节输入流对象,封装到输入字符流中
BufferedReader br1=new BufferedReader(in);//将字符流套入buffer流中while(br1.readLine()!=null){//读取buffered缓冲流中的数据
System.out.println(br1.readLine());
}
uc.getOutputStream();//建立网络字节输出流对象,经过这个流把客户端的数据上传到服务端,经过输出流写入数据叫作上传
OutputStreamWriter out=new OutputStreamWriter(uc.getOutputStream());//建立网络输出字节流对象,封装到输出字符流中
BufferedWriter bw=new BufferedWriter(out);//将字符流套入buffer流中
bw.flush();
7 使用第四层协议TCP协议来通讯
服务器至关于中介转发做用
7.一、Socket通讯:
ServerSocket :用在服务端,建立时须要给定端口号,调用accpet()方法,对用户在指定端口上的请求作监听 ss=new ServerSocket(port); ss.accpet();
Socket:客户端经过Socket向该端口发送链接请求 Socket(host,port);
客户端和服务端都要建立两个流,服务端的getInputStream()从信道中读取数据,客户端也能够建立网络本身输入流读取数据。服务端和客户端均可以建立getOutputStream()能够把信息写入信道中。 客户端只能从信道中读取服务端放入信道中的数据,服务端也只能读取客户端放入信道中的数据。(全双工理论)
先走服务端,ServerSocket在4331端口上建立服务端对象,调用accpet()方法,返回的对象为Socket类型。
客户端创建链接请求,new Socket(“localhost”,4331);,一旦没有出异常,信道就已经建立了.客户端经过mySocket建立网络字节输入流对象,从信道中读数据到客户端,mySocket建立网络字节输出流对象,输出数据到信道中。
若是服务端和客户端一块儿从信道中读取信息会产生死锁。
mySocket(客户端)
DataOutputStream out=new DataOutputStream(mySocket.getOutputStream());//客户端获取输出数据流 out.writeUTF(“你好”);//客户端往信道中写入数据给服务端
DataInputStream out=new DataInputStream(mySocket.getInputStream());//客户端获取输入数据流 out.readUTF();//客户端从信道中读取服务端写入的数据
you(服务端)
DataOutputStream out=new DataOutputStream(you.getOutputStream());//服务端获取输出数据流 out.writeUTF(“你也好”);//服务端往信道中写入数据给客户端
DataInputStream out=new DataInputStream(you.getInputStream());//服务端获取输入数据流 out.readUTF();//服务端从信道中读取客户端写入信道中的数据
readUTF();//一次只能读取一个字符串
链接时,先开启服务器,断开链接时,先断开客户端。
InetAddress复写了toString():显示主机名+IP地址
协议名:规定访问资源的方式(file:本地访问,http:浏览器)
URL url=new URL(“file:/f:/t.txt”);
url.openStream();//字节输入流
客户端在同一时刻能够读取信道中的数据和写入数据到信道中。服务端也能够在从信道中读取数据的时候同时写入数据到信道中。由于客户端和服务端有两个虚信道。 只须要避免客户端和服务端都从信道中读取数据,而且信道中没有数据的时候就不会产生死锁。
1 UDP协议(无序不可靠可是高效)
先把数据放在数据报中,数据以字节数组对象的形式放入数据报中。
String str=”abcdefg”;
byte[] buf=str.getBytes();//将字符串变为字节数组对象
一个类中至少要有两个线程,一个线程负责发送数据,另外一个线程负责接收数据。(也有可能发送数据的时候正好接收数据了)
上海用Thread线程接收北京发送的数据,上海在主线程经过actionPerformed方法向端口号8888发送信息,北京经过调用Thread线程所执行的run方法中8888端口号中接收信息。 主线程用来发送数据,Thread线程用来接收数据。
主线程是虚拟机建立的,另一个线程应该在主线程主方法中建立。
class BeiJing extends Frame implements ActionListener,Runnable{
public BeiJing(){
Thread thread=new Thread(this);//在构造方法中建立线程对象,用于对方接收信息
thread.start();//启动接收数据的线程
this.addActionListener(this);
}
//响应发送数据报按钮事件(发信)
public void actionPerformed(ActionEvent e){
byte[] buf=textOut.getText().trim().getBytes();//拿到输出文本框的内容
InetAddress address=InetAddress.getByName(“localhost”);//获得地址
DatagramPacket dp=new DatagramPacket(buf,buf.length,address,port);//把数据封装到数据报(相似于把信放入信箱中)
DatagramSocket ds=new DatagramSocket();//邮递员
ds.send(dp);//发送数据报
}
//对方接收信息(收信)
public void run(){
byte[] buf=new byte[8192];//空的字节数组对象
DatagramPacket dp=new DatagramPacket(buf,buf.length);//空的数据报
DatagramSocket ds=new DatagramSocket(port);//在port端口上建立邮递员
ds.receive(dp);//接收数据(收到的数据存入空的数据报dp中)
dp.getPort();//获取发送端端口号
dp.getAddress();//获取发送端的IP地址
dp.getLength();//获取接收到的数据的长度
dp.getData();//是一个字节数组对象
String message=new String(dp.getData());//将字节数组对象变为字符串
textIn.setText(message);//将接收到的数据设置到
textIn.append(“hahaha”);//在文本框中追加数据
}
frame.pack();//自动调整组件大小
}
2 多波协议(群发消息)
MulticastSocket:多播套接字
InetAddress group=InetAddress.getByName(“239.255.8.0”);// 获得多播组地址对象
MulticastSocket socket=new MulticastSocket(port);//指定播送消息的套接字,邮递员
socket.joinGroup(group);//加入多播组
接收端和发送端的group和port应该是相同的。
调用线程的interrupt()方法,线程从封锁态进入就绪态
接收端:
在public void actionPerformed(ActionEvent e){} 方法中建立一个线程,new Thread(this); 接收信息类实现 Runnable接口。
在public void run(){}方法中接收信息。
建立空字节数组byte[] buf=new byte[8192];
建立空数据报new DatagramPacket(buf,buf.length,group,port)(指定group,port 接收端和发送端相同),
MuticastSocket多播套接字为邮递员。 socket.receive(dp);//将数据放入数据报中 dp.getData();//获得数据报中的数据,为字节数组类型
String message=new String(dp.getData());//将字节数组变为字符串
中止接收按钮响应: thread.interrupt();//只应用一个线程处于封锁状态
继续设置标志位 flag=true;
thread.interrupt()方法一执行,接收线程会执行catch中的代码,在catch代码块中判断flag的值,为true时 break。
3 Java聊天室(多线程,接口,GUI 事件突发机制)
服务器建立ServerSocket对象 new ServerSocket(port,10);//端口号和最大链接数
对于最大限度用户数,服务器端应该用线程池或者线程集合。重点在服务端。
为多个用户建立信道,同时为多个用户服务。
经过线程对象拿到信道,得到流
怎么管理10个线程对象?
线程数组来维护多个线程对象。定义一个线程继承了Thread类,复写run方法,提供个有参的构造方法。在服务端定义该类的线程数组,使用数组管理多个线程对象。
private ServerThread[] serThread=new ServerThread[maxClients];
serThread[i]=new ServerThread(ss.accept(),i);//建立服务器线程,i表示等待链接线程数
serThread[i].start();//启动线程
下线:
定义一个下线数组,10个元素 int[],先判断全部上线的人数,再判断下线人数
用for循环判断用户是否已经下线(用户ID)
for(int m=0;m<onlineClients;m++){//对上线人数的循环
boolean flag=true;//标记用户是否为上线状态:true表示已上线,false:表示已下线
for(int j=0;j<outlineID;j++){//对上线后又下线了的人数的循环
if(i==outline[j]){//判断用户i是否已经下线,若是i不在下线数组里面表示它以成功上线
flag=false;
break;//跳出本层循环
}
}
私聊:
if((!message.equals(""))&&(message!=null)&&(message.startsWith("*"))){//判断是否为私聊信息
StringTokenizer str=new StringTokenizer(message,"*"); //截取出以*号分隔的的字符 *12*qwe 截取后结果为: 12
num=Integer.parseInt(str.nextToken());//获得信息接收端目的用户
serThread[num].output.writeUTF(message);//将信息写给目的用户
服务端接收信息,客户端发送信息
StringTokenizer(str,”*”);//用*分隔字符串
公聊:
双重for循环,把信息发给每个在线的用户
for(int i=0;i<onlineClients;i++){
boolean flag=false;
for(int k=0;k<outline.length;k++){
if(i==outline[k]){
flag=true;
break;
}
}
if(flag){
try {
serThread[i].output.writeUTF(ID+"号用户刚刚下线了");
}catch (IOException e1) {
e1.printStackTrace();
}
}
}
问题?
用户下线后,此用户还能继续上线嘛?
不能,由于线程数组已经满了,下线后内存已经被占。此现象称为假溢出
能够用集合来存储线程对象,也能够用线程池
聊天时只有一个服务器,只须要先开启而且开启一次就好,客户端能够开启多个,相互发送消息。
周末做业:
聊天室,TCP协议,UDP协议。版本各一个,使用线程池或者集合数组存储线程对象
多播协议聊天实例:
服务端:
//服务端
public void actionPerformed(ActionEvent e6){
byte[] buf=textOut.getText().trim().getBytes();//将文本框中须要发送的数据变成字节数组对象
try {
InetAddress address=InetAddress.getByName("239.255.8.0");//端口号必须为D类地址 240.0.0.0-239.255.255.255
MulticastSocket ms=new MulticastSocket();//多播邮递员
ms.joinGroup(address);//加入多播组织
DatagramPacket dp=new DatagramPacket(buf,buf.length,address,23342);//将数据打包
ms.send(dp);//发送数据
} catch (UnknownHostException e1) {
e1.printStackTrace();
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}}
客户端:
//启动线程接收用户发来的数据
public void run(){
while(true){
byte[] buf=new byte[8192];//建立空的字节数组对象,接收多播发过来的数据
try {
InetAddress addr=InetAddress.getByName("239.255.8.0");//指定接收同一广播地址的广播
DatagramPacket dp=new DatagramPacket(buf,buf.length);//准备好数据包接收数据
MulticastSocket ms=new MulticastSocket(23342);//监听多播端口号
ms.joinGroup(addr);//加入多播组织
ms.receive(dp);//接收数据
String message=new String(dp.getData());//将接收过来的数据变为字符串类型
textIn.append(message+"\n");//存入文本输出域中
System.out.println("lalala__"+message);
} catch (UnknownHostException e1) {
e1.printStackTrace();
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} }
B GRVFC