java基础编程笔记3

一、switch语句

/*

1、default 里面可以没有break;进入switch语句后,一旦满足其中一个条件,若没有遇到break;语句,程序会一直执行到结束。default语句可以放在switch句末,也可以放在switch句首。执行顺序还是先执行case后执行switch。default位置是可选的。

2、switch(变量)变量中只能存放char byte short int string(jdk1.7)

3、case(条件)中,条件只能是值,不能是取值范围。

4、变量跟条件的类型需要保持一致,不一致会报错。

*/

public static void main(String[] args) {

switch (5) {
default:
System.out.println("other");
case 1:System.out.println(1);
break;
case 2:System.out.println(2);
break;
case 3:System.out.println(3);
break;

}

}


Math 类中提供了三个与取整有关的方法:ceil、floor、round,这些方法的作用与它们的英
文名称的含义相对应,例如,ceil 的英文意义是天花板,该方法就表示向上取整,
Math.ceil(11.3)的结果为12,Math.ceil(-11.3)的结果是-11;floor 的英文意义是地板,该方法
就表示向下取整,Math.ceil(11.6)的结果为11,Math.ceil(-11.6)的结果是-12;最难掌握的是
round 方法,它表示“四舍五入”,算法为 Math.floor(x+0.5),即将原来的数字加上0.5后再向
下取整,所以,Math.round(11.5)的结果为12,Math.round(-11.5)的结果为-11。


二、关于数组:不管是静态初始化还是动态初始化,一定在创建的时候,就指明了数组的长度!


三:关于重载

要求:1、同一个类中  2、方法名必须相同  3、方法的参数列表不同(①参数的个数不同 ②参数类型不同  ③参数的顺序不同)

注:看方法是否重载只需从方法名称开始看起;可变参数的形参的方法与同名的方法之前构成重载   如public void print(string args){} 和 public void print(String...args){}  如果方法的参赛列表不同,则返回值类型可以不同。

四、类及类的构成成分:属性 方法 构造器 代码块 内部类

五、可变个数的形参的方法:
public int getSum(int...args){
int sum=0;
for (int i : args) {
sum+=i;
}
return sum;
}
1、格式:对于方法的形参:数据类型...形参名
2、可变可数的形参的方法与同名的方法之间构成重载
3、可变个数的形参在调用时,个数从0开始,到无穷多个都可以
4、使用可变多个形参的方法与方法的形参使用数组是一致的
5、若方法中存在可变个数的形参,那么一定要声明在方法形参的最后
6、在一个方法中,最多声明一个可变个数的形参。

六、权限修饰符  从大到小  所有范围-》子类-》同包-》同类  分别对应  public  protected 默认 private

注: public  protected 默认 private都可以用于类的成员,用于类的权限修饰符时只能用public 和默认修饰符

七、构造器
1、设计类时,若不显示声明类的构造器的话,程序会默认提供一个空参的构造器。
2、一旦显式地定义类的构造器,那么默认的构造器就不再提供(若仍需要空参的构造器需要显式地定义)
3、声明类的构造器。格式:权限修饰符 类名(形参){}
4、类的多个构造器之间形成重载

八、this关键字
1、可以用来修饰属性、方法、构造器
2、this理解为当前对象或当前正在创建的对象。比如:this.name  ,this.show();
3、可以在构造器中通过“this(形参)”的方式显示的调用本类中其他重载的指定的构造器。
要求:1)、在构造器的内部必须声明在首行!
   2)、若一个类中有N个构造器,那么最多有n-1个构造器中使用了this(形参)

九、JavaBean
JavaBean是一种Java语言写成的可重用组件。
所谓JavaBean,是指符合如下标准的Java类:
1、类是公共的
2、有一个无惨的公共的构造器
3、有属性,且有对应的get、set方法

十、继承
1、方式   class A extends B 
2、子类继承父类后,父类中声明的属性、方法,子类就可以获取到。
注意:当父类中私有的属性或方法时,子类同样可以获取到,只是由于封装性的设计,使得子类不可以直接调用罢了。
3、继承只支持单继承:一个类只能支持一个父类。反之,一个父类可以有多个父类
4、子类父类是相对的概念

十一、重写(也叫覆盖、覆写)
1、前提:有子类继承父类
2、子类继承父类以后,若父类的方法对子类不适用,那么子类可以对父类的方法重写(override  overwrite)
3、重写的规则:1 )子类方法的修饰符不能小于父类方法的修饰符
   2)子父类的方法必须同为static或同为非static的。
   3)要求子类方法的“返回值类型  方法名(参数列表)”与父类的方法一样
   4)若父类方法抛异常,那么子类方法抛的异常不能大于父类的

十二、super
1、当子类与父类中有同名的属性时,可以通过"super.此属性"显示的调用父类中声明的属性。若想调用子类的同名的属性"this.此属性"
2、当子类重写父类的方法以后,在子类中若想再显示的调用父类的被重写的方法,就需要使用"super.方法"
3、super修饰构造器:通过在子类中使用"super(形参列表)"来显示的调用父类中指定的构造器。
1)在构造器内部,"super(形参列表)"必须要声明在首行!
2)在构造器内部,"this(形参列表)"或"super(形参列表)"只能出现一个!
3)当构造器中,不显示的调用"this(形参列表)”或“super(形参列表)”其中任何一个,默认调用的是父类空参的构造器!
建议:一个类中要尽量地提供一个空参的构造器(特别是有提供有参构造器的时候更应该提供,若不提供,子类在没有显示调用构造器的时候回默认调用父类的空参构造器,这时候系统会提示没有该构造器)

十三、多态性
Java引用变量有两个类型:编译时类型和运行时类型。编译时类型由声明给变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。
若编译时类型和运行时类型不一致,就出现多态(polymorphism).
instanceof 格式:对象a instanceof  类A  
1、子类对象的多态性使用的前提:①要有类的继承 ②要有子类对父类方法的重写
2、程序运行分为编译状态和运行状态
对于多态性来说,编译时,“看左边”,将此引用变量理解为父类的类型
运行时,“看右边”,关注于真正对象的实体:子类的对象。那么执行的方法就是子类重写的。
3、多态性的作用:有利于方法的设计(即形参只需要写父类的名称就可以)
4、子类的属性没有多态性

十四、equals()
先谈谈与equals()方法相关的另一个比较符"=="
“==”号的使用时跟常量池的概念密不可分的
看例子:
//“==”号比较的是两边的“值”而不是“内容”
// String 类型是特殊的对象类型(类型声明中“String”中的“S”是大写的,符合对象声明的要求),
// 之所以说它是特殊的,是因为它提供了常量池(对象池)技术
// 使用“==”比较的是两个变量在栈空间的值
// 使用equals()比较为true的两个变量,在常量池中地址是一定相同的,但是在堆空间有可能是不一样的
String s1="abc";
String s2="ab"+"c";
String s3=new String("abc");
String s4=new String("ab")+"c";
System.out.println(s1==s2);//true 声明s1时,在常量池开辟了空间存放“abc",s2没有new,也是存放在常量
             池,s2指向“abc”
System.out.println(s1==s3);//false
System.out.println(s1==s4);//false
System.out.println(s2==s3);//false
System.out.println(s2==s4);//false
System.out.println(s3==s4);//false
System.out.println(s1.equals(s2));//true
System.out.println(s1.equals(s3));//true
System.out.println(s1.equals(s4));//true
System.out.println(s2.equals(s3));//true
System.out.println(s2.equals(s4));//true
System.out.println(s3.equals(s4));//true

//int a=10 是直接声明一个变量a,然后给它赋值10;
// Integer a=10 由于a是一个类变量,存放的是引用,a是通过引用来间接存放10这个值的
// 基本数据类型中,声明为原始数据类型的数据,
// java中基本类型的包装类的大部分都实现了常量池技术,这些类是Byte,Short,Integer,
// Long,Character,Boolean,另外两种浮点数类型的包装类则没有实现。
// 另外Byte,Short,Integer,Long,Character这5种整型的包装类也只是在对应值大于等于-128小于等于127时才可使用对象池
int i1=3;//3存放在栈空间
int i2 = 1 + 2; // 在栈空间开辟空间存放
int i3 = new Integer(3);//自动拆箱
int i4 = new Integer(1) + 2;//自动拆箱
System.out.println(i1 == i2);// true
System.out.println(i1 == i3);// true
System.out.println(i1 == i4);// true
System.out.println(i2 == i3);// true
System.out.println(i2 == i4);// true
System.out.println(i3 == i4);// true
System.out.println();
Integer i5=127;
Integer i6=127;
Integer i7=128;
Integer i8=128;
Integer i9=new Integer(127);
Integer i10=new Integer(127);
int i11=127;
int i12=128;
System.out.println(i5==i6);//true 常量池  缓存  -128到127
System.out.println(i7==i8);//false 
System.out.println(i9==i10);//false 两个new出来的变量地址永远是不一样的,因为分别在内存开辟了新的空间
System.out.println(i5==i11);//true  自动拆箱  变成比较两个int类型的值
System.out.println(i7==i12);//true 自动拆箱,所有与原始数据类型比较的封装类都会自动拆箱
System.out.println(i9==i11);//true 自动拆箱  i9拆箱后是127再与i11比较
System.out.println();
int i=65;
Character c='A';
System.out.println(i==c);//true 自动拆箱,所有与原始数据类型比较的封装类都会自动拆箱

Byte b=2;
Integer i=2;
System.out.println(b.equals(i));//因为类型不同,所以会输出false  equals()比较的是两个类变量是否一致,//当类型不一致时,即返回false,不再进一步运算。

1、Object 的equals() 方法比较的仍然是两个变量的地址值是否相等
2、String类、包装类、File类、Date类这些类重写了Object 类的equals()方法,比较的是两个对象的“实体内容”是否相同

Boolean b=new Boolean("cdd");
System.out.println(b);//false

基本数据类型、包装类、String类之间的转换
1、基本数据类型跟包装类:自动装箱拆箱
2、基本数据类型和String类:1)基本数据类型转换为String类型 String类的valueOf(形参)或  +“ ”
  2)String类型转换为基本数据类型:调用相应包装类的parseXxx(String)

静态方法。或者通过包装类构造器,如boolean b=new Boolean("true");
3、String 类型转换为包装类  调用对应包装类的构造器

Static 关键字
static修饰属性(类变量):
1、由类创建的所有的对象,都共用这一个属性
2、当其中一个对象属性进行修改,其他对象的属性也会发生改变
3、类变量是随着类的加载而加载的,而且独一份
4、静态的变量可以直接通过“类.类变量”的形式来调用
5、类变量的加载是要早于对象
6、类变量存在于静态域中

静态的方法内是不可以有this或super关键字的(因为非static的属性、方法前面默认是有this关键字的,代表当前对象)
单例模式
1、私有化构造器,使得在类的外部不能调用此构造器
2、在类的内部创建一个类的实例
3、私有化此对象,通过公共的方法来调用
4、此公共的方法,只能通过类来调用,因此设置为static的,同时类的实例也必须为static声明的
class  Singleton{//恶汉式
private Singleton(){

}
private static Singleton singleton=new Singleton();
public static Singleton getSingleton(){
return singleton;
}
}


class  Singleton{//懒汉式-存在线程安全问题
private Singleton(){

}
private static Singleton singleton=null;
public static Singleton getSingleton(){
if (singleton==null) {
singleton=new Singleton();
}
return singleton;
}
}

代码块的执行要先于构造器
关于属性赋值的操作:①默认的初始化②显示的初始化或代码块初始化(此处两个结构按照顺序执行)
③构造器中④通过调用方法
构造器是初始化的最后一道屏障
方法没有被调用的时候是不会自动执行的

程序的执行顺序
父类的静态代码块-子类的静态代码块-父类的普通初始化块-父类的无参的构造器-子类的普通初始化块-子类的无惨的构造器

final 
1、final标记的类不能被继承  如String类、System类、StringBuffer类
2、final标记的方法不能被子类重写 如Object类中的getClass()
3、final标记的变量(成员变量或局部变量)即称为常量。名称大写,且只能被赋值一次。
final标记的成员变量必须在声明的同时或在每个构造方法中或代码块中显示赋值(不能使用默认赋值方式),然后才能使用。 如final double PI=3.14  

变量用static  final修饰:全局常量

abstract :抽象的,可以用来修饰类、方法
抽象类
1)不可被实例化
2)有构造器 (可以定义构造器)凡是类都有构造器
3)抽象方法所
4)抽象类中可以没有抽象方法。

抽象类与普通类的唯一区别:就是不能创建实例对象和允许有 abstract 方法。


抽象方法
1)格式:没有方法体,包括{}.如public abstract void eat();
2)抽象方法只保留方法的功能,而具体的方法,交给继承抽象类的子类,由子类重写此抽象方法。
3)若子类继承抽象类,并重写了所有的抽象方法,则此类是一个“实体类”,即可用实例化。
4)若子类继承抽象类,没有重写所有的 抽象方法,意味着此类中仍有抽象方法,则此类必须声明为抽象的!    
abstract 不能用来修饰属性(方法可以覆盖、属性无法覆盖,没有意义)、构造器(因为构造器不能被重写)、private(子类不能够覆盖声明为private的方法)、final(final方法不能被重写)、static(static修饰的方法是属于类的,定义成abstract没有意义)

接口是抽象方法和常量值的定义的集合。
从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现。
一个类可以实现多个接口,接口也可以继承其他接口。
接口是没有构造器的
interface 中所有的常量都用public static final
interface 中所有的方法都用public abstract修饰
接口与接口之间是继承的关系,而且可以实现多继承

十五、工厂模式
public class TestFactoryMethod {
public static void main(String[] args) {
WorkFactory swf=new StudentWorkFactory();
swf.getWork().work();//老师批改作业
WorkFactory twf=new TeacherWorkFactory();
twf.getWork().work();//学生写作业
}
}
interface Work{
void work();
}
class TeacherWork implements Work{
@Override
public void work() {
System.out.println("学生写作业");
}
}
class StudentWork implements Work{
@Override
public void work() {
System.out.println("老师批改作业");
}
}
interface WorkFactory{
Work getWork();
}
class TeacherWorkFactory implements WorkFactory{
@Override
public Work getWork() {
return new TeacherWork();
}
}
class StudentWorkFactory implements WorkFactory{
@Override
public Work getWork() {
return new StudentWork();
}
}

十六、静态代理模式
public class TestFactoryMethod {
public static void main(String[] args) {
Object obj=new ProxyObject();
obj.action();
}
}
interface Object{
void action();
}
//被代理类
class ObjectImpl implements Object{
@Override
public void action() {
System.out.println("被代理类的方法开始执行");
}

}
//代理类
class ProxyObject implements Object{
Object obj;
public ProxyObject(){
System.out.println("代理类创建成功");
obj=new ObjectImpl();
}
public void action(){
ystem.out.println("代理类的方法开始执行");
obj.action();
}
}

十七、内部类
1、内部类的分类:成员内部类(声明在类内部且方法外的)  局部内部类(声明在类的方法里)
2、成员内部类  2.1是外部类的一个成员:①可以有修饰符(4个) ②static final  ③可以调用外部类的属性方法
  2.2具体类的特点:①abstract  ②还可以在其内部定义属性、方法、构造器


成员内部类的调用(分静态跟非静态)
public class TestInnerClass {
public static void main(String[] args) {
Animal.Dog.print();//调用静态内部类
new Animal().new Bird().print();//调用非静态内部类
}
}
class Animal{
class Bird{
public void print(){
System.out.println("我是一只鸟");
}
}
static class  Dog {
public static void print(){
System.out.println("我是一只狗狗");
}
}
}

内部类调用属性
public class TestInnerClass {
public static void main(String[] args) {
new Animal().new Dog().print("形参");
}
}
class Animal{
String name="Animal";
class Dog{
String name="Dog";
public void print(String name){
System.out.println(name);//调用形参
System.out.println(this.name);//调用内部类的属性 Dog
System.out.println(Animal.this.name);//调用外部类的属性 Animal 
}
}
}

十八、异常
Java.lang.Throwable
|----Error:错误。程序中不进行处理
|----Exception:异常,要求在编写程序时,就要考虑到对这些异常的处理。
|----编译时异常:在编译期间会出现的异常(执行javac.exe命令时,出现异常)
|----运行时异常:在运行期间出现的异常(执行Java.exe命令时,出现异常)


常见的运行时异常:
1、数组下标越界的异常:ArrayIndexOutOfBoundsException
2、算术异常:ArithmeticException
3、类型转换异常:ClassCastException
4、空指针异常:NullPointerException

注:1、try内声明的变量,类似于局部变量,出了try{}语句,就不能被调用
2、finally是可选的。
3、catch语句内部是对异常对象的处理。
》e.getMessage();    》e.printStackTrace
4、可以有多个catch 语句,try中抛出的异常类对象从上往下去匹配catch中的异常类的类型,一旦满足就执行catch中的语句。执行完,就跳出其后的多条catch语句
5、finally中存放的是一定会被执行的代码,不管try中、catch中是否仍有异常未被处理,以及是否有return语句语句。

Java的异常处理:抓抛模型
1、抓:异常的处理,有两种方式(①try-catch-finally ②throws+异常的类型)
2、抛:一旦执行过程中,出现异常,会抛出一个异常类的对象。(自动的抛出(系统遇到问题自动抛出)VS 手动的抛出(throw+异常的对象))

抛出的异常类型:若是RuntimeException,可以不显示的处理
若是一个Exception,必须要显示的处理(因为Exception包括编译时异常,系统会要求进行处理)

如何自定义一个异常类
1、自定义的异常类继承现有的异常类
2、提供一个序列号,提供几个重载的构造器
class MyException extends RuntimeException{
static final long serialVersionUID = -7034897190745766939L;
public MyException() {
super();
// TODO Auto-generated constructor stub
}
public MyException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
}

十九、集合
Java集合框架
1、Iterator 迭代器接口
2、Collection子接口之一:Set接口  HashSet  LinkedHashSet  TreeSet 
3、Collection子接口之二:List接口 ArrayList  LinkedList  Vector
4、Map接口  HashMap  TreeMap  HashTable 
5、Collections工具类

Set:元素无序、不可重复的集合
List:元素有序,可重复的集合
Collection接口的方法
1、contains(Object obj) :判断集合中是否包含obj,返回boolean类型。判断的依据是元素所在类的equals()方法。
要求:若存入集合中的元素是自定义类的对象,要求自定义类重写equals()方法!
2、ratainAll(Collection  coll):求当前集合与coll的共有元素,返回给当前集合

Collection元素的迭代:
方法一:不使用
Iterator iterator=coll.iterator();
for (int i = 0; i <coll.size(); i++) {
System.out.println(iterator.next());
}
方法二:
Iterator iterator=coll.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}

方法三:
for (Object object : collection) {
System.out.println(object);
}

判断list是否有且只有一个元素“123”
System.out.println(list.indexOf(123)==list.lastIndexOf(123));

ArrayList(List的主要实现类) LinkedList(对应频繁插入、删除操作) Vector(古老的、线程安全的,但效率要低于ArrayList)

Set:存储的元素是无序的,不可重复的!
1、无序性:无序性!=随机性。真正的无序性,指的是元素在底层存储的位置是无序的。
2、不可重复性:当向Set中添加进相同的元素的时候,后面的这个不能添加进去。
说明:要求添加进Set 中的类,一定要重写equals()和hashCode()方法。进而保证Set集合中元素的不可重复性。因为Set是使用哈希算法进行存储的。当向Set中添加对象时,首先调用此对象所在类的hashCode()方法,计算此对象的哈希值,此哈希值决定了Set 中的存储位置。若此位置之前没有对象存储,则这个对象直接存储到此位置。若此位置已有对象存储,再通过equals()比较这两个对象是否相同。如果相同,后一个对象就不能再添加进来。万一返回false,都存储。(不建议如此)
要求:hashCode()方法要与equals()方法一致。
总结:set添加对象时,有且只有当两个对象的hashCode()返回相同的的哈希值、equals()方法都返回true时,两个对象才才不会被重复添加。

LinkedHashSet:使用链表维护了一个添加进集合中的顺序。导致当我们遍历LinkedHashSet集合元素时,是按照添加进去的顺序遍历的! LinkedHashSet插入性能略低于HashSet,但在迭代访问Set里的全部元素时有很好的性能。

TreeSet:
1、向TreeSet中添加的元素必须是同一个类型的。
2、可以按照添加进集合中的元素的指定的顺序遍历。像String,包装类等默认按照从小到大的顺序遍历。
3、当向TreeSet中添加自定义类的对象时,有两种排序方法:①自然排序 ②定制排序 若有同时提供自然排序和定制排序,则默认是使用定制排序的
4、自然排序:要求自定义类实现Java.lang.Comparable接口并重写其comparaTo(Object obj)的抽象方法,在此方法
中,指明按照自定义类的哪个属性排序。
5、向TreeSet中添加元素的时候,首先按照compareTo()进行比较,一旦返回0,虽然仅是此两个对象的此属性相同,但是程序会认为这两个对象时相同的,进而后一个对象不能添加进来。
要求:compareTo()与hashCode()以及equals()三者保持一致!

题目:对于两个对象A、B,A.equals(B)==true,不一定有相同的hashCode(); 这句话是错误的。java的Object类中规定相同的对象一定要有相同的hashCode

自定义排序:
1、创建一个实现了Comparetor接口的类,并重写compare(Object o1,Object o2)方法;
2、将此对象传递给TreeSet的构造器中;
3、向TreeSet中添加Comparetor接口中的compare(Object o1,Object o2)方法中涉及类的对象。
compara()与hashCode()以及equals()三者保持一致!

Map与Collection并列存在。用于保存具有映射关系的数据:Key-Value
Map中的key和value都可以是任何引用类型的数据
Map中的key用Set来存放,不允许重复,即同一个Map对象所对应的类,需重写hashCode()和equals()方法。
key和value之间存在单向一对一关系,即通过指定的key总能找到唯一的、确定的value。

Map接口(跟Collection是并列的)
实现类有HashMap(Map的主要实现类)LinkedMap TreeMap HashMap(Properties是其子类)
HashMap:key是用Set来存放的,不可重复。value是用Collection来存放的,可重复。一个key-value对,是一个Entry。所有的Entry是用Set存放的,也是不可重复的。

向HashMap中添加元素时,会调用key所在类的equals()方法,判断两个key是否相同。若相同则只能添加进后添加的哪个元素。故Map中增加和修改都是使用put(Object o1,Object o2)方法。

Map map=new HashMap();
map.put("aa", 23);
map.put("bb", 24);
map.put("cc", 25);
map.put("dd", 26);
map.put("ee", 27);
Set keySet=map.keySet();
for (Object object : keySet) {
System.out.println(object);
}
Collection collection=map.values();
for (Object object : collection) {
System.out.println(object);
}
Set set=map.entrySet();
for (Object object : set) {
Map.Entry<Object, Object> entry=(Entry<Object, Object>) object;
System.out.print(entry.getKey());
System.out.println(entry.getValue());
}

TreeMap:按照添加进Map中的元素的key的指定属性进行排序。要求:key必须是同一个类的对象。
针对key:自然排序vs定制排序

Hashtable是个古老的Map实现类,线程安全。不建议使用
与HashMap不同,HashMap不允许使用null作为key和value。
Hashtable的子类Properties类:常用来处理属性文件。键和值都为String类型的。

Properties properties=new Properties();//Properties类存储的key-value对都是String类型的
properties.load(new FileInputStream(new File("jdbc.properties")));
String username=properties.getProperty("username");
String password=properties.getProperty("password");
System.out.println(username);
System.out.println(password);

在工程目录下新建“jdbc.properties”,内容如下:
username=\u9648\u6653\u57CE
password=abc123

     Collection集合的遍历是通过Iterator   Map集合的遍历是通过entrySet

      泛型(generic)
Map<Integer, String> map=new HashMap<Integer, String>();
map.put(1, "aa");
map.put(2, "bb");
map.put(3, "cc");
Set<Map.Entry<Integer, String>> set=map.entrySet();
//遍历
for (Map.Entry<Integer, String> entry : set) {
System.out.println(entry.getKey());
System.out.println(entry.getValue());
}

如果我们自定义了泛型,但是在实例化时没有使用,那么默认类型是Object类的。
继承泛型类或泛型接口时 ,可以指明泛型类的类型。

DAO:database access object 数据库访问对象

定义泛型方法(需要在返回值位置前面加泛型类型符合):
public <E> E getE(E e){
return e;
}

泛型与继承的关系:
若类A是类B的子类,那么List<A>就不是List<B>的子接口。

 List<Object> oList=null;
 List<String> sList=new ArrayList<>();
//  oList=sList;//编译无法通过
 List<?> oList2=null;//使用通配符
 List<String> sList2=new ArrayList<>();
 oList2=sList2;//编译可以通过

?extends A:可以存放A及其子类
? super A:可以存放A及其父类

泛型的思想:把一个集合中的 内容限制为一个特定的数据类型,这就是generic背后的核心思想。
不能在catch中使用泛型。
静态方法中不能使用类的泛型。

使用通配符的集合的遍历:
List<String> list=new ArrayList<>();
 list.add("AA");
 list.add("BB");
 List<?> list1=list;
 Iterator<?> iterator=list1.iterator();
 while (iterator.hasNext()) {
System.out.println(iterator.next());
 }

可以读取声明为通配符的集合类的对象
不允许向声明为通配符的集合类中写入对象。唯一例外的是null.

枚举类
1、如何自定义枚举类;
2、如何使用enum自定义枚举类 ,enum有哪些常用的方法;
3、实现接口的枚举类

枚举类如何实现接口:①让类实现此接口,类的对象共享同一套接口的抽象方法的实现。
②让类的每一个对象去实现接口的抽象方法,进而通过类的对象调用被重写的抽象方法时,执+行的效果不同。

若枚举只有一个成员,则可以作为一种单例模式的实现方式。
自定义枚举类
public class TestSeason {
public static void main(String[] args) {
Season spring=Season.SPRING;
System.out.println(spring);
System.out.println(spring.getSeasonName());
}
}
class Season{
// 1、提供类的属性,声明为private final
private final String seasonName;
private final String seasonDesc;
// 2、声明为final的属性,在构造器中初始化
private Season(String seasonName,String seasonDesc){
this.seasonName=seasonName;
this.seasonDesc=seasonDesc;
}
// 3、通过公共的方法来调用
public String getSeasonName() {
return seasonName;
}
public String getSeasonDesc() {
return seasonDesc;
}
// 4、创建枚举类的对象:将类的对象声明为public static final
public static final Season SPRING=new Season("spring", "春暖花开");
public static final Season SUMMER=new Season("summer", "夏日炎炎");
public static final Season AUTUMN=new Season("autumn", "秋高气爽");
public static final Season WINTER=new Season("winter", "白雪皑皑");
@Override
public String toString() {
return "Season [seasonName=" + seasonName + ", seasonDesc="
+ seasonDesc + "]";
}
public void show(){
System.out.println("这是一个季节");
}
}

使用enum定义枚举类
public class TestSeason1 {
public static void main(String[] args) {
Season spring=Season.SPRING;
System.out.println(spring);
System.out.println(spring.getSeasonName());
System.out.println();
// 1、values();
Season1[] seasons=Season1.values();
for (Season1 season1 : seasons) {
System.out.println(season1);
}
// 2、valueOf()
Season1 season1=Season1.valueOf("SPRING");
System.out.println(season1);
}
}
enum Season1{
// 定义的对象必须放到最前面,public static final Season1去除,对象之间用“,”隔开。
SPRING("spring", "春暖花开"),
SUMMER("summer", "夏日炎炎"),
AUTUMN("autumn", "秋高气爽"),
WINTER("winter", "白雪皑皑");
private final String seasonName;
private final String seasonDesc;
private Season1(String seasonName,String seasonDesc){
this.seasonName=seasonName;
this.seasonDesc=seasonDesc;
}
public String getSeasonName() {
return seasonName;
}
public String getSeasonDesc() {
return seasonDesc;
}
@Override
public String toString() {
return "Season [seasonName=" + seasonName + ", seasonDesc="
+ seasonDesc + "]";
}
public void show(){
System.out.println("这是一个季节");
}
}

注解Annotation
1、JDK内置的基本注解类型(3个);
2、自定义注解类型;
3、对注解进行注解(元注解);
4、利用反射获取注解信息(在反射部分涉及)

IO流
绝对路径:包括盘符在内的完整的文件路径;、
相对路径:在当前文件目录下(工程)的文件的路径。
file 对应着一个文件或者一个文件夹。

file1.renameTo(file2):当file1和file2同为文件夹且不在同一个文件目录下时,是将file1转到file2文件目录下面。注意:file1必须是存在的,file2必须是不存在的。

File类的mkDir()和mkDirs()的区别:
mkDir():创建一个文件目录。只有在上层文件目录存在的情况下,才能返回true
mkDirs():创建一个文件目录。若上层文件目录不存在,一并创建。

节点流(4个):FileInputStream、FileOutputStream、FileReader、FileWriter
抽象基类(4个);InputStresam、OutputStream、Reader、Writer
流的分类:
按照数据流向的不同:输入流 输出流
安装处理数据的单位的不同:字节流 字符流(只能处理文本文件)
按照角色的不同:节点流(直接作用于文件的) 处理流(除了节点流以外的,用于包装节点流的流)

读入文件
public static void main(String[] args) {
FileInputStream fis=null;
try {
File file=new File("test.txt");
fis=new FileInputStream(file);
byte[] b=new byte[5];
int length;
while ((length=fis.read(b))!=-1) {
String str=new String(b, 0, length);
System.out.print(str);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if (fis!=null) {
try {
fis.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
}

写入文件
public static void main(String[] args) {
FileOutputStream fos=null;
try {
File file=new File("myTest.txt");
fos=new FileOutputStream(file);
fos.write("I love China ,I love the World".getBytes());
fos.flush();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if (fos!=null) {
try {
fos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}


将文件1复制到文件2:
public static void main(String[] args) {
FileInputStream fis=null;
FileOutputStream fos=null;
try {
File intFile=new File("C:\\Users\\Administrator\\Desktop\\1.jpg");
File outFile=new File("C:\\Users\\Administrator\\Desktop\\2.jpg");
fis=new FileInputStream(intFile);
fos=new FileOutputStream(outFile);
byte[] b=new byte[20];
int length;
while ((length=fis.read(b))!=-1) {
fos.write(b, 0, length);
fos.flush();
// fos.write(b);//错误的写法1
// fos.write(b,0,b.length);//错误的写法2
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(fos!=null){
try {
fos.close();
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
if(fis!=null){
try {
fis.close();
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}

/*
* 使用FileReader跟FileWriter可以实文本文件的复制,对于非文本文件,只能使用字节流。
*/
public static void main(String[] args) {
FileReader frd=null;
FileWriter fwd=null;
try {
File intFile=new File("C:\\Users\\Administrator\\Desktop\\新建文本文档.txt");
File outFile=new File("C:\\Users\\Administrator\\Desktop\\投诉内容.txt");
frd=new FileReader(intFile);
fwd=new FileWriter(outFile);
char[] c=new char[20];
int lentth;
while ((lentth=frd.read(c))!=-1) {
fwd.write(c, 0, lentth);
fwd.flush();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if(fwd!=null){
try{
fwd.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(frd!=null){
try {
frd.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

使用BufferedOuputStream和BufferedWriter时,需要使用 flush()方法。BufferedInputStream和BufferedReader的区别:BufferedReader可以使用readerLine()方法,该方法在没有的内容的时候,返回null
换行的方法:+“\n” newLine()

使用BufferedInputStream和BufferedOutputStream复制文件
public void copyFile(){
BufferedInputStream bis=null;
BufferedOutputStream bos=null;
try {
File file=new File("C:\\Users\\Administrator\\Desktop\\1.wmv");
File file2=new File("C:\\Users\\Administrator\\Desktop\\2.wmv");
FileInputStream fis=new FileInputStream(file);
FileOutputStream fos=new FileOutputStream(file2);
bis=new BufferedInputStream(fis);
bos=new BufferedOutputStream(fos);
byte[] b=new byte[1024*1024];
int length ;
while ((length=bis.read(b))!=-1) {
bos.write(b, 0, length);
bos.flush();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if (bos!=null) {
try {
bos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (bis!=null) {
try {
bis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

解码:字节数组-》字符串
编码:字符串-》字节数组
转换流:InputStreamReader、OutputStreamWriter
使用转换流输入复制文件
public static void main(String[] args) {
BufferedReader br=null; 
BufferedWriter bw=null;
try {
File file=new File("myTest.txt");
File file2=new File("myTest2.txt");
FileInputStream fis=new FileInputStream(file);
FileOutputStream fos=new FileOutputStream(file2);
InputStreamReader isr=new InputStreamReader(fis, "GBK");
OutputStreamWriter osw=new OutputStreamWriter(fos,"GBK");
br=new BufferedReader(isr);
bw=new BufferedWriter(osw);
String str;
while ((str=br.readLine())!=null) {
bw.write(str);
bw.newLine();
bw.flush();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if (bw!=null) {
try {
bw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (br!=null) {
try {
br.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

/*
* 标准的输入、输出流:System.in   System.out 
* 试题:从键盘输入字符串,要求将读取到的整行字符读取成大写输出。然后继续进行输入操作。
* 直至当输入"d"或者"e"时,退出程序。
*/
public static void main(String[] args) {
BufferedReader br=null;
try {
java.io.InputStream is=System.in;
InputStreamReader isr=new InputStreamReader(is);
br=new BufferedReader(isr);
String str;
while (true) {
str=br.readLine();
if (str.equalsIgnoreCase("d")||str.equalsIgnoreCase("e")) {
break;
}
System.out.println(str.toUpperCase());
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if (br!=null) {
try {
br.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

打印流:PrintStream(处理字节) PrintWriter(处理字符)
PrintStream p=new PrintStream(new FileOutputStream("hello.txt".true);

数据流:用来处理基本数据类型、String、字节数组的数据:DataInputStream、DataOutputStream

/*
 * 使用DateOutputStream将数据输出到文件
 */
@Test
public void test1(){
DataOutputStream dos=null;
 try {
FileOutputStream fos=new FileOutputStream("test3.txt");
 dos=new DataOutputStream(fos);
 dos.writeBoolean(true);
 dos.writeUTF("我爱你,但你却不知道");
 dos.writeUTF("我爱你,但你却不知道");
 dos.writeUTF("我爱你,但你却不知道");
 dos.writeInt(1253456789);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if (dos!=null) {
try {
dos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/**
 * 使用DataIntputStream实现从文件将数据读入到控制台
 */
@Test
public void test2(){
DataInputStream dis=null;
try {
FileInputStream fis=new FileInputStream("test3.txt");
dis=new DataInputStream(fis);
System.out.println(dis.readBoolean());;
System.out.println(dis.readUTF());
System.out.println(dis.readUTF());
System.out.println(dis.readInt());
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if (dis!=null) {
try {
dis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

/*
 * 使用DateOutputStream将数据输出到文件
 */
@Test
public void test1(){
DataOutputStream dos=null;
 try {
FileOutputStream fos=new FileOutputStream("test3.txt");
 dos=new DataOutputStream(fos);
 dos.writeBoolean(true);
 dos.writeUTF("我爱你,但你却不知道");
 dos.writeUTF("我爱你,但你却不知道");
 dos.writeUTF("我爱你,但你却不知道");
 dos.writeInt(1253456789);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if (dos!=null) {
try {
dos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/**
 * 使用DataIntputStream实现从文件将数据读入到控制台
 */
@Test
public void test2(){
DataInputStream dis=null;
try {
FileInputStream fis=new FileInputStream("test3.txt");
dis=new DataInputStream(fis);
System.out.println(dis.readBoolean());;
System.out.println(dis.readUTF());
System.out.println(dis.readUTF());
System.out.println(dis.readInt());
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if (dis!=null) {
try {
dis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
 
/*
 * 序列化的好处在于可将任何实现了Serializable接口的对象转化为字节数据,使其在保存和传输时可被还原。
     如何需要让某个对象支持序列号机制,则必须让某类是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一:
Serializable
Externalizable
序列化:用ObjectOutputStream类将一个Java对象写入IO流中
反序列化:用ObjectInputStream类从IO流中恢复该Java对象
 */
public class ObjectInputOutputStream {
public static void main(String[] args) {

}
/*
* 反序列化
*/
@Test
public void testObjectInputStream(){
ObjectInputStream ois=null;
try {
ois=new ObjectInputStream(new FileInputStream("Person.txt"));
Pet pet=(Pet) ois.readObject();
Person person=(Person) ois.readObject();
System.out.println(pet);
System.out.println(person);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if (ois!=null) {
try {
ois.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/*
* 序列化
*/
@Test
public void testObjectOutputStream(){
ObjectOutputStream oos=null;
try {
Pet pet=new Pet("小花");
Person person=new Person(123, "王烁柔", pet);
oos=new ObjectOutputStream(new FileOutputStream("Person.txt"));
oos.writeObject(pet);
oos.flush();
oos.writeObject(person);
oos.flush();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if (oos!=null) {
try {
oos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
/*
 * 要实现序列化的类:
1、要求此类是可序列化的:实现Serializable接口
2、要求类的属性同样的要实现Serializable接口
3、提供一个版本号:private static final long serialVersionUID
4、使用static 或transient修饰的属性,不可实现序列化。
 */
 
class Person implements Serializable{
private static final long serialVersionUID=33333444222445l;
Integer id;
String name;
Pet pet;
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", pet=" + pet + "]";
}
public  Person(Integer id, String name, Pet pet) {
super();
this.id = id;
this.name = name;
this.pet = pet;
}
}
class Pet implements Serializable{
private static final long serialVersionUID=33333444444l;
String name;
@Override
public String toString() {
return "Pet [name=" + name + "]";
}
public  Pet(String name) {
super();
this.name = name;
}
}

/*
 * RandomAccessFile:支持随机访问
 * 1、既可以充当一个输入流,又可以充当一个输出流
 * 2、支持从文件的开头读取、写入
 * 3、支持从任意位置的读取、写入(插入)
* 4、若输出的文件不存在,直接创建。若存在,则是对原有文件内容的覆盖(而不是对文件的覆盖)。
 */
public class TestRandomAccessFile {
/*
* 实现在有多行的情况下,在某个位置插入字符的效果
*/
@Test
public void test3(){
RandomAccessFile raf=null;
try {
raf=new RandomAccessFile("test.txt", "rw");
raf.seek(4);
// byte[] b=new byte[10];
// int len;
// StringBuffer sb=new StringBuffer();
// while ((len=raf.read(b))!=-1) {
// sb=sb.append(new String(b, 0, len));
// }
StringBuffer sb=new StringBuffer();
String str;
while ((str=raf.readLine())!=null) {
sb=sb.append(str+"\n");
}
raf.seek(4);
raf.write("CXC".getBytes());
raf.write(sb.toString().getBytes());
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if (raf!=null) {
try {
raf.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/*
* 在文件的某个位置插入字符串,这种方法实际上实现的是覆盖效果。
*/
@Test
public void test2(){
RandomAccessFile raf=null;
try {
raf=new RandomAccessFile("test.txt", "rw");
raf.seek(4);
raf.write("xy".getBytes());
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if (raf!=null) {
try {
raf.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/*
*  进行文件的读、写
*/
@Test
public void test1(){
RandomAccessFile raf1=null;
RandomAccessFile raf2=null;
try {
raf1=new RandomAccessFile(new File("test.txt"), "r");
raf2=new RandomAccessFile(new File("test2.txt"), "rw");
byte[] b=new byte[10];
int len;
while ((len=raf1.read(b))!=-1) {
raf2.write(b,0,len);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if (raf2!=null) {
try {
raf2.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (raf1!=null) {
try {
raf1.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}

模仿Scanner写一个类MyScanner
class MyScanner{
public String nextString(){
BufferedReader br=null;
String str=null;
try {
InputStreamReader isr=new InputStreamReader(System.in);
br=new BufferedReader(isr);
str = br.readLine();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return str;
}
public int nextInt(){
return Integer.parseInt(nextString());
}
public double nextDouble(){
return Double.parseDouble(nextString());
}
}

多线程
程序:可以理解为静态的代码
进程:可以理解为执行中的程序
线程:可以理解为进程的进一步细分,程序的一条执行路劲。

/*
 * 创建一个子线程,完成1-100之间自然数的输出。同样地,主线程执行同样的操作
 * 
 */
public class TestThread {
public static void main(String[] args) {
// 3、创建一个子类的对象
SubThread sub1=new SubThread();
// 4、调用线程的start():启动此线程,调用相应的run()方法。
sub1.start();
// 一个线程只能执行一个start();Thread的start()和run()方法是两个不同的方法,
// 不能通过调用实现类的run()方法来启用线程。调用run()方法只是普通的地调用该方法。
SubThread sub2=new SubThread();
sub2.start();
for (int i = 1; i<=100; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
//1、创建一个继承Thread 的子类
class SubThread extends Thread{
// 2、重写Thread类的run()方法。方法内实现此子线程要完成的功能。
public void run(){
for (int i = 1; i<=100; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}

Thread的方法
yield()方法,强制让当前线程释放CPU的执行权。放弃之后当前线程重新加入对CPU资源的抢夺,仍然有可能继续执行。
join(),在A线程中调用B线程的join()方法,表示:当执行到此方法,A线程停止执行,直至B线程执行完毕,A线程再接着join()之后的代码执行。
isAlive():pand存活。
sleep(long l):显示的让当前线程睡眠l毫秒。
线程通讯:wait() notify() notifyAll()
设置线程的优先级:①getPriority():返回线程优先值 ②setPrority(int new Priority):改变线程的优先级

/*
 * 继承方法实现火车站多窗口售票
 * 此种方式实现多窗口售票存在线程安全问题
 * 
 */
public class TestThread {
 public static void main(String[] args) {
Window window1=new Window("窗口1");
Window window2=new Window("窗口2");
Window window3=new Window("窗口3");
window1.start();
window2.start();
window3.start();
}
}
class Window extends Thread{
static int ticket=100;
public void run(){
while (ticket>0) {
try {
Thread.currentThread().sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖出第 "+ticket--+" 张票");
}
}
public Window(String name){
super(name);
}
}

/*
 * 创建多线程的方式二:通过实现Runnable的方式(只要是多线程,都要跟Runnable发生关系,Thread本身是实现Runnable接口的)
 */
public class TestThread1 {
public static void main(String[] args) {
PrintNum p=new PrintNum();
Thread t1=new Thread(p);
Thread t2=new Thread(p);
t1.start();
t2.start();
}
}
class PrintNum implements Runnable{
@Override
public void run() {
for (int i = 1; i <=100; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}


多线程的两种实现方式哪一种好(继承Thread类的方式与实现Runnable的接口的方式):
实现的方式优于继承的方式:理由①避免了java单继承的局限性 ②如果多个线程要操作同一份资源,如火车票余票,更适合使用实现的方法。

如何解决线程的安全问题:必须让一个线程操作共享数据完毕后,其它线程才有机会参与共享数据的操作。

线程的同步机制:
方式一:同步代码块
synchronize(同步监视器){需要被同步的代码块(即为操作共享数据的代码)}
1、共享数据:多个线程共同操作的同一个数据(变量)
2、同步监视器:由一个类的对象来充当。哪个线程获取此监视器,谁就执行大括号里被同步的代码。俗称:锁
方式二:同步方法
3、同步监视器必须定位为成员变量,不能定义为局部变量,即被用来作为锁的对象必须定义在方法外面。需要在实现Runnable接口的类的同步代码块中才能使用this作为同步锁。用继承的方法同步代码块需要使用static 的Object对象实例作为同步锁。
/*
 * 继承的方式使用同步锁
 */
public class TestThread1 {
public static void main(String[] args) {
MyThread myThread1=new MyThread("线程1");
MyThread myThread2=new MyThread("线程2");
MyThread myThread3=new MyThread("线程3");
myThread1.start();
myThread2.start();
myThread3.start();
}
}
/*
 * 继承的方式使用同步锁
 * 作为锁的对象必须使用定义为static的。
 */
class MyThread extends Thread{
static int ticket=300;
static Object obj=new Object();
@Override
public void run() {
while (true) {
synchronized(obj){
if (ticket>0) {
// try {
// Thread.currentThread().sleep(10);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
System.out.println(Thread.currentThread().getName()+"售卖第: "+ticket--+" 张票");
}else {
break;
}
}
}
}
public MyThread(String name) {
super(name);
// TODO Auto-generated constructor stub
}
}

/*
 * 实现的方式使用同步锁
 */
public class TestThread1 {
public static void main(String[] args) {
Window window=new Window();
Thread thread1=new Thread(window);
Thread thread2=new Thread(window);
Thread thread3=new Thread(window);
thread1.setName("线程1");
thread2.setName("线程2");
thread3.setName("线程3");
thread1.start();
thread2.start();
thread3.start();
}
}
/*
 * 实现的方式使用同步锁
 * 锁(同步监视器)可以使用this
 */
class Window implements Runnable{
static int ticket=100;
@Override
public void run() {
// TODO Auto-generated method stub
while (true) {
synchronized (this) {
if (ticket > 0) {
try {
Thread.currentThread().sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ " 售卖第  " + ticket-- + " 张票");
} else {
break;
}
}
}
}
}


同步方式二:同步方法
将操作共享数据的方法声明为synchronize,即此方法为同步方法,能够保证其中一个线程执行此方法时,其它线程再外等待直至此线程执行完此方法。
同步方法的锁是当前对象,即this。正因为如此,继承Thread类的方式使用同步方法实现线程同步存在线程安全问题。(同步的“同”是指“协同”

/*
 * 同步方法实现线程的同步
 */
class Window implements Runnable{
int ticket=100;
@Override
public void run() {
// TODO Auto-generated method stub
while (true) {
show();
}
}
public synchronized void show(){//使用同步方法时,同步锁是当前对象。
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "  "
+ ticket--);
}  
}
}

无论是使用实现的方式还是使用同步的方式实现多线程,都需要重写run()方法,都需要通过调用start()方法来启用线程。start()方法是Thread类的。所以使用实现Runnable接口的方法实现多线程的时候,必须将实现类作为形参传给Thread,通过thread的实例来调用start()。

对应一般的方法内,使用同步代码块,可以考虑(当前对象只有一个时)使用this
对应静态方法而言,使用当前类本身充当锁。

/*
 * 懒汉式实现线程安全
 */
public class TestThread1 {
public static void main(String[] args) {
 Mythread mythread=new Mythread();
 Thread thread1=new Thread(mythread);
 Thread thread2=new Thread(mythread);
 thread1.start();
 thread2.start();
}
}
class Mythread implements Runnable{
@Override
public void run() {
Singleton singleton=Singleton.getSingleton();
System.out.println(singleton);
}
}
class Singleton{
private Singleton(){

}
private static Singleton instance=null;
public static Singleton getSingleton(){
if (instance==null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}

释放锁的操作:执行wait()方法,当前线程暂停,并释放锁。
注:sleep()方法时不会释放锁的。

线程通信涉及到的3个方法:wait()、notify()、notifyAll(),这3个方法是定义在Object类中,而不是定义在Thread类中
这3个方法只有在synchronized方法或synchronized代码块中才能使用,否则会报IllegalMonitorStateException异常。

/*
 * 使用线程通信实现两个线程交替打印数字
 */
public class TestAccount {
public static void main(String[] args) {
PrintNum printNum=new PrintNum();
Thread thread1=new Thread(printNum);
Thread thread2=new Thread(printNum);
thread1.setName("线程1");
thread2.setName("线程2");
thread1.start();
thread2.start();
}
}
class PrintNum implements Runnable{
int num=100;
@Override
public void run() {
// TODO Auto-generated method stub
while (true) {
synchronized (this) {
notify();
if (num > 0) {
System.out.println(Thread.currentThread().getName() + ":  "
+ num--);
} else {
break;
}
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}

/*
 * 生产者消将产品交给店员(Clerk),而消费者(Customer)从店员处取走产品,店员一次只能持有固定数量的产品(比如:20),如果
 * 生产者试图生产更多的产品,店员会叫停生产者停一下,如果店中有空位放产品了再通知生产者继续生产;如果店中没有产品了,店员
 * 会告诉消费者等一下,如果店中有产品了再通知消费者来取走产品。
 */
public class TestAccount {
public static void main(String[] args) {
 Clerk clerk=new Clerk();
 Producer producer=new Producer(clerk);
 Customer customer=new Customer(clerk);
 Thread thread1=new Thread(producer);
 Thread thread2=new Thread(producer);
 Thread thread3=new Thread(customer);
 thread1.setName("生产者1");
 thread2.setName("生产者2");
 thread3.setName("消费者");
 thread1.start();
 thread2.start();
 thread3.start();
}
}
class Clerk{
int product;
public synchronized void addProduct(){//生产产品
if (product>=20) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else {
System.out.println(Thread.currentThread().getName()+":生产了第    "+(++product)+" 个产品");
notify();
}
}
public synchronized void consumeProduct(){
if (product<=0) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else {
System.out.println(Thread.currentThread().getName()+":消费了第    "+(product--)+" 个产品");
notify();
}
}
}
class Customer implements Runnable{
Clerk clerk;
public Customer(Clerk clerk) {
// TODO Auto-generated constructor stub
this.clerk=clerk;
}
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("消费者开始消费");
while (true) {
try {
Thread.currentThread().sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
clerk.consumeProduct();
}
}
}
class Producer implements Runnable{
Clerk clerk;
public Producer(Clerk clerk) {
// TODO Auto-generated constructor stub
this.clerk=clerk;
}
@Override
public void run() {
System.out.println("生产者开始生产产品");
// TODO Auto-generated method stub
while (true) {
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
clerk.addProduct();
}
}
}

String s1="hellow";
String s2="world";
String s3="hellowworld";
String s4=s1+s2;
String s5=s4.intern();
System.out.println(s3==s4);//false 此时s4在常量池开辟了另一个存储空间
System.out.println(s3==s5);//true  将s4拼接后的字符串在常量池进行比较,若已有该字符串,将指针指向该字符串。
System.out.println(s4==s5);//false 

String :代表不可变的字符序列。底层使用char[] 存放。String是final的。

//public boolean regionMatches(int firstStart,  
//                String other,//判断当前字符串从firstStart 开始,len个字符的子串与other字符串从otherStart开始,len个字//符的子串相比是否相等。
//                int otherStart,
//                int len)
String s1="abcdefgh";
String s2="cdef";
System.out.println(s1.regionMatches(3, s2, 1, 2));

String s1="abcdefghijk";
System.out.println(s1.replaceAll("def", "刘德华"));//abc刘德华ghijk
System.out.println(s1);//abcdefghijk

/*
 * 1、模拟trim方法,去除字符串两端的空格。(注意全是空格的情况)
 * 2、将字符串指定部分进行反转。比如"abcdefg"反转为"abfedcg" (有三种方法)
 * 3、获取一个字符串在另一个字符串出现的次数。比如:“ab" 在"abefdfdab fdsf ab"中出现的次数
 * 4、获取两个字符串中最大相同子串。注意程序的死循环   比如:str1="abcwerthelloyuiodef" str2="cvhellobnm" 
 *    提示:将短的那个串进行长度依次递减的子串与较长的串比较。
 * 5、对字符串中字符进行自然顺序排序。
 */
public class StringDemo {
public static void main(String[] args) {
// String str=" dffdf   ";
// System.out.println(myTrim(str));


// String str="abcdefg";
// System.out.println(reverse1(str, 2, 5));


// String str="abcdefg";
// System.out.println(reverse2(str, 2, 5));

// String str="abcdefg";
// System.out.println(reverse3(str, 2, 5));
//
// String str1="abefdfdab fdsf ababababababa";
// String str2="abz";
// System.out.println(getTime(str1,str2));

// String str1="abcwerthelloyuiodef";
// String str2="cvhellobnhellom";
// System.out.println(getMaxSubString(str1, str2));;

System.out.println(mySort("sdfdsewdzdfd")); 

}
/*
* 5、对字符串中字符进行自然顺序排序。
*/
public static String mySort(String str){
char[] c=str.toCharArray();
Arrays.sort(c);
return new String(c);
}
/*
* 4、获取两个字符串中最大相同子串。注意程序的死循环   比如:str1="abcwerthelloyuiodef" str2="cvhellobnm" 
               提示:将短的那个串进行长度依次递减的子串与较长的串比较。
*/
public static List<String> getMaxSubString(String str1,String str2){
List<String> list=new ArrayList<>();
String maxStr=str1.length()>str2.length()?str1:str2;
String minStr=str1.length()<str2.length()?str1:str2;
int len=minStr.length();
for (int i = 0; i <len; i++) {//需要比i轮
for (int j = 0; j <=i; j++) {//第i轮需要比len-i个字符,拿j到j+len-i个字符与他比。
String str=minStr.substring(j,j+len-i);
if (maxStr.contains(str)) {
list.add(str);
}
}
if (list.size()>0) {
return list;
}
}
return null;
}
/*
* 3、获取一个字符串在另一个字符串出现的次数。比如:“ab" 在"abefdfdab fdsf ab"中出现的次数
*/
public static int getTime(String str1,String str2){
StringBuffer sb=new StringBuffer(str1);
int index;
int time = 0;
while ((index=sb.indexOf(str2))!=-1) {
time+=1;
sb.delete(0, index+str2.length());
}
return time;
}
/*
* 2、将字符串指定部分进行反转。比如"abcdefg"反转为"abfedcg" 方法一
*/
public static String  reverse1(String str,int start,int end){
char[] c=str.substring(start,end+1).toCharArray();
char temp;
for (int i = 0,j=c.length-1; i < c.length&&i<j; i++,j--) {
temp=c[i];
c[i]=c[j];
c[j]=temp;
}
return str.substring(0,start)+new String(c)+str.substring(end+1,str.length());
}
/*
* 2、将字符串指定部分进行反转。比如"abcdefg"反转为"abfedcg" 方法二
*/
public static String  reverse2(String str,int start,int end){
String string=str.substring(start,end+1);
StringBuffer sb=new StringBuffer();
int length=string.length();
while(--length>=0){
sb.append(string.charAt(length));
}
return str.substring(0,start)+sb.toString()+str.substring(end+1,str.length());
}
/*
* 2、将字符串指定部分进行反转。比如"abcdefg"反转为"abfedcg" 方法三
*/
public static String  reverse3(String str,int start,int end){
return str.substring(0,start)
+new StringBuffer(str.substring(start,end+1)).reverse()
+str.substring(end+1,str.length());
}
/*
* 1、模拟trim方法,去除字符串两端的空格。(注意全是空格的情况)
*/
public static String  myTrim(String str){
int i=0;
int len=str.length()-1;
while(str.charAt(i)==' '&&i<len){
i++;
}
while(str.charAt(len)==' '&&i<len){
len--;
}
if (" ".equals(str.substring(i,len+1))) {
return "";
}else {
return str.substring(i,len+1);
}
}
}

StringBuffer代表可变的字符序列,可以对字符串内存进行增删。
StringBuffer是一个容器。


StringBuffer sb=new StringBuffer();
sb.append("abcdefg");
Person person=new Person(3,"陈晓城");
sb.append(person);
System.out.println(sb);//abcdefgcom.atguigu.java1.Person@bcda2d   注意:此时


Person类没有重写toString()方法
sb=sb.delete(3, 4);
System.out.println(sb);//abcefgcom.atguigu.java1.Person@bcda2d
sb.reverse();
System.out.println(sb);//d2adcb@nosreP.1avaj.ugiugta.mocgfecba
sb.substring(3);
System.out.println(sb);//d2adcb@nosreP.1avaj.ugiugta.mocgfecba  注意:


substring()方法并没有改变原来的字符串。
 
总结:
添加:append()  删除 delete(int i,int j)   修改  setCharAt(int index,char ch)  查询charAt(int 


n)  插入insert(int index,String str)  反转:reverse() 


StringBuilder与StringBuffer一样也是可变的字符序列,两者之间有以下区别:
1、StringBuffer是线程安全的,StringBuilder是线程不安全的;
2、StringBuilder效率比StringBuffer快。  效率对比:StringBuilder>StringBuffer>String


日期时间相关的四个类:
System类  Date类  SimpleDateFormat类  Calendar类


Date类
构造方法:
Date()  使用Date类的无惨数构造方法创建的对象可以获取本地当前时间。
Date(long date) 
常用方法:
getTime()返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。
toString(): 把此 Date 对象转换为以下形式的 String: dow mon dd hh:mm:ss zzz yyyy 其中: dow 


是一周中的某一天 (Sun, Mon, Tue, Wed, Thu, Fri, Sat)。


SimpleDateFormat类  
Date类的API不易于国际化,大部分被废弃了,Java.text.SimpleDateFormat类是一个不与语言环境相关的


方式来格式化和解析的具体类。
它允许进行格式化(日期-》文本)、解析(文本-》日期)
格式化:
SimpleDateFormat():默认的模式和语言环境创建对象
public SimpleDateFormat(String pattern):该构造方法可以用参数pattern指定的格式创建一个对象,该对象调用:
public String format(Date date):方法格式化时间对象date
解析:
public Date parse(String source):从给定字符串的开始解析文本,以生成一个日期。


SimpleDateFormat sdf=new SimpleDateFormat();
System.out.println(sdf);//java.text.SimpleDateFormat@b5341f2a
System.out.println(sdf.format(new Date()));//17-8-8 下午3:18
SimpleDateFormat sdf1=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf1.format(new Date()));//2017-08-08 15:26:40
//解析日期
Date date1=sdf.parse("17-8-8 上午3:30");
System.out.println(date1);//SimpleDateFormat的构造器是什么格式的就只能解析什么格式的的字符串。
Date date2=sdf1.parse("2017-08-08 15:26:40");
System.out.println(date2);


/*
* “三天打鱼两天晒网”  1991-01-01开始 XXXX-XX-XX 是在打鱼?晒网?
*/
public static void show() throws ParseException{
String str1="1991-01-01";
String str2="1991-01-03";
if (getDays(str1, str2)%5==0||getDays(str1, str2)%5==4) {
System.out.println("晒网");
}else {
System.out.println("打鱼");
}
}
public static  int getDays(String date1,String date2) throws ParseException{
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
Date d1=sdf.parse(date1);
Date d2=sdf.parse(date2);
long time=d2.getTime()-d1.getTime();
return (int) (time/1000/3600/24)+1;
}

Calendar类:
Calendar calendar=Calendar.getInstance();
System.out.println(calendar.DATE);
BigInteger bi=new BigInteger("1243241123");
BigDecimal bd=new BigDecimal("12435.351");
BigDecimal bd2=new BigDecimal("11");
System.out.println(bi);
// System.out.println(bd.divide(bd2));//错误的写法,当无法除尽的时候需要指定精度
(保留位数和舍入方式)
System.out.println(bd.divide(bd2,BigDecimal.ROUND_HALF_UP));//按默认的保留位
数(小数点后3位)四舍五入求值
System.out.println(bd.divide(bd2,15,BigDecimal.ROUND_HALF_UP));//按小数点后15
位的精度四舍五入方求值

反射:
Reflection(反射)是被称为动态语言的关键,它能借助Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
Java反射机制提供的功能
1、在运行时判断任意一个对象所属的类
2、在运行时判断任意一个类的对象
3、在运行时判断任意一个类所具有的成员变量和方法
4、在运行时判断任意一个对象的成员变量和方法
5、生成动态代理

反射内容
1、理解Class类并实例化Class类对象(重点)
2、运行时创建类对象并获取类的完整结构
3、通过反射调用类的指定方法、指定属性(重点)
4、动态代理

关于反射相关的类都位于lang包下。

//1、创建clazz对应的运行时类Person类的对象
Class<Person>  clazz=Person.class;
Person p=(Person) clazz.newInstance();
// 2、通过反射调用声明为public的属性并进行赋值
Field field=clazz.getField("name");
System.out.println(field);
field.set(p, "陈晓城");
System.out.println(p);
// 3、通过反射调用声明为非public的属性并进行赋值
Field field2=clazz.getDeclaredField("age");
field2.setAccessible(true);
field2.set(p, 27);
System.out.println(p);
// 4、通过反射调用方法
Method m1=clazz.getMethod("show");
m1.invoke(p);//调用无惨的方法
Method m2=clazz.getMethod("display", String.class);//方法名,类型
m2.invoke(p, "中国");//调用有参的方法

/*
* 我们创建了一个类,通过编译(javac.exe),生成对应的.class文件。之后我们使用java.exe加载(JVM的类加载器完成的)此.class文件,此.class文件加载到内存以后,就是一个运行时类,存在缓存区。那么这个运行时类本身就是一个Class的类!
* 1、每一个运行时类只加载一次!
* 2、有了Class的实例以后,我们才可以进行如下的操作:
* 1)创建对应的运行时类的对象
* 2)获取对应的运行时类的完整结构(属性、方法、构造器、内部类、父类、所在的包、异常、注解)
* 3)调用对应的运行时类指定的结构(属性、方法、构造器)
* 4)反射的应用:动态代理
*/
@Test
public void test1() throws ClassNotFoundException{
// Class是反射的源头
// 获取Class实例的四种方法
String className="com.atguigu.java1.Person";
Class clazz1=Person.class;
Class clazz2=new Person().getClass();
Class clazz3=Class.forName(className);
Class clazz4=this.getClass().getClassLoader().loadClass(className);
//通过类加载器的loadClass(String args) ,作为了解
System.out.println(clazz1==clazz2);
System.out.println(clazz1==clazz3);
System.out.println(clazz1==clazz4);
}

initializationError:可能为方法独立运行时未加“@Test”

/*
* 使用ClassLoader可以用来干什么:
* 使用classLoader.getResourceAsStream("com/atguigu/java1/jdbc.properties");读取具体某个包下面的文件
*/
@Test
public void testClassLoader() throws IOException{
ClassLoader classLoader=this.getClass().getClassLoader();
InputStream is=classLoader.getResourceAsStream("com/atguigu/java1/jdbc.properties");
Properties properties=new Properties();
properties.load(is);
System.out.println(properties.getProperty("username"));
System.out.println(properties.getProperty("password"));
}
/*
* 使用properties.load(new FileInputStream(new File("jdbc2.properties"))),读取当前工程目录(根目录)下的文件
*/
@Test
public void testProperties () throws FileNotFoundException, IOException{
Properties properties=new Properties();
properties.load(new FileInputStream(new File("jdbc2.properties")));
System.out.println(properties.getProperty("username"));;
System.out.println(properties.getProperty("password"));;
}

理解类加载器:
JVM在运行时会产生3个类加载器:
1、引导类加载器:使用C++ 编写的,是JVM自带的类加载器,负责Java平台核心库,用来加载核心类库。该加载器无法直接获取。
2、扩展类加载器:负责jre/lib/ext目录下的jar包或-D java.ext.dirs指定目录下的jar包装入工作库。
3、系统类加载器:负责java-classpath或-D java.class.path所指的目录下的类与jar包装入工作,是最常用的加载器。
ClassLoader classLoader1=ClassLoader.getSystemClassLoader();
System.out.println(classLoader1);//sun.misc.Launcher$AppClassLoader@164dbd5 系统类加载器
ClassLoader classLoader2=classLoader1.getParent();
System.out.println(classLoader2);//sun.misc.Launcher$ExtClassLoader@9cb0f4  扩展类加载器
ClassLoader classLoader3=classLoader2.getParent();
System.out.println(classLoader3);// null  无法直接获取引导类加载器
ClassLoader classLoader4=Person.class.getClassLoader();
System.out.println(classLoader4);//sun.misc.Launcher$AppClassLoader@164dbd5 系统类加载器

有了Class对象后,可以通过Class对象的newInstance()方法创建类的对象。
要求:1)类必须有一个无惨的构造器。
2)类的构造器的访问权限需要足够。

//获取运行时类的属性
@Test
public void test1(){
Class clazz=Person.class;
//1.getFields():只能获取运行时类及其父类中声明为public的属性
Field[] fields=clazz.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println();
//2、getDeclaredFields()只能获取运行时类本身(不包括父类)声明的所有属性。
Field[] fields2=clazz.getDeclaredFields();
for (Field field : fields2) {
System.out.println(field);
}
}
//权限修饰符 变量类型  变量名
//获取属性的各个部分的内容
@Test
public void test2(){
Class clazz=Person.class;
//1.getFields():只能获取运行时类及其父类中声明为public的属性
Field[] fields2=clazz.getDeclaredFields();
for (Field field : fields2) {
//1、获取权限修饰符 ,会显示public static 
int i=field.getModifiers();
String str1=Modifier.toString(i);//转化为String
System.out.print(str1+"  ");
//2、获取属性的类型
Class type=field.getType();
System.out.print(type.getName()+" ");
//3、获取属性名
System.out.print(field.getName()+" ");
System.out.println();
}
}

//1、获取运行时类的方法
@Test
public void test1() throws ClassNotFoundException{
Class clazz=Class.forName("com.atguigu.java1.Person");
//1、getMethods():获取运行时类及其父类中所有的声明为public的方法
Method[] methods=clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println();
//2、getDeclaredMethods():获取运行时类本身声明的所有的方法
Method[] methods2=clazz.getDeclaredMethods();
for (Method method : methods2) {
System.out.println(method);
}
}
//注解  权限修饰符 返回值类型 方法名 形参列表  异常
@Test
public void test2(){
Class clazz=Person.class;
Method[] methods2=clazz.getDeclaredMethods();
for (Method method : methods2) {
// 1、注解
Annotation[] annotations=method.getAnnotations();
if (annotations.length!=0) {
for (Annotation annotation : annotations) {
System.out.print(annotation);
}
System.out.println();
}
// 2、权限修饰符
System.out.print(Modifier.toString(method.getModifiers())+" ");
// 3、返回值类型
System.out.print(method.getReturnType().getName()+" ");
// 4、方法名
System.out.print(method.getName());
// 5、形参列表
System.out.print("(");
Class[] typeClazz=method.getParameterTypes();
if (typeClazz.length>0) {
for (int i = 0; i < typeClazz.length; i++) {
System.out.print(typeClazz[i].getName()+" "+"args"+i+" ");
}
}
System.out.print(") ");
// 6、异常
Class[] exceptions=method.getExceptionTypes();
if (exceptions.length>0) {
System.out.print("throws ");
for (int i = 0; i < exceptions.length; i++) {
System.out.print(exceptions[i].getName());
if (i!=exceptions.length-1) {
System.out.print(",");
}
}
}
System.out.println();
}
}

//6、获取注解(类的注解)
@Test
public void test6(){
Class clazz=Person.class;
Annotation[] annotations=clazz.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
}
// 5、获取所在的包
@Test
public void test5(){
Class clazz=Person.class;
System.out.println(clazz.getPackage());;
}
// 4、获取实现的接口
@Test
public void test4(){
Class clazz=Person.class;
Class[] interfaces=clazz.getInterfaces();
for (Class class1 : interfaces) {
System.out.println(class1);
}
}
// 3、获取父类的泛型(掌握)
@Test
public void test3(){
Class clazz=Person.class;
Type type1=clazz.getGenericSuperclass();
ParameterizedType param=(ParameterizedType) type1;
Type[] ars=param.getActualTypeArguments();
System.out.println(((Class)ars[0]).getName());
}
// 2、获取带泛型的父类
@Test
public void test2(){
Class clazz=Person.class;
System.out.println(clazz.getGenericSuperclass());
}
// 1、获取运行时类的父类
@Test
public void test1(){
Class clazz=Person.class;
System.out.println(clazz.getSuperclass());
}

//调用运行时类中指定的属性
@Test
public void test() throws Exception{
//1、获取指定的属性
//getField(String fieldName):获取运行时类中声明为public 的指定属性为fieldName的属性
Class clazz=Person.class;
//2、创建运行时类的对象
Field name=clazz.getField("name");
Person person=(Person) clazz.newInstance();
//3、将运行时类的指定的属性赋值
name.set(person, "晓明");
System.out.println(person);
//getDeclaredField(String fieldName):获取运行时类中指定的fieldName的属性
Field age=clazz.getDeclaredField("age");
//由于属性权限修饰符的限制,为了保证可以给属性赋值,需要在操作前使得此属性可被操作。
age.setAccessible(true);
age.set(person, 20);
System.out.println(person);
}
//调用运行时类中指定的方法
@Test
public void test2() throws Exception{
Class clazz=Person.class;
Method m1=clazz.getMethod("show");
Person person=(Person) clazz.newInstance();
//调用指定的方法:invoke(Object obj,Object...obj)
m1.invoke(person);

Method m2=clazz.getMethod("toString");
Object returnVal1=m2.invoke(person);
System.out.println(returnVal1);

Method m3=clazz.getMethod("info");
m3.invoke(Person.class);
//getDeclaredMethod(String methodName,Class...params):获取运行时类中声明的方法
Method m4=clazz.getDeclaredMethod("display",String.class);
m4.setAccessible(true);
m4.invoke(person,"中国");
}
//调用指定的构造器,创建运行时的对象
@Test
public void test3() throws Exception{
String className="com.atguigu.java1.Person";
Class clazz=Class.forName(className);
Constructor constructor=clazz.getDeclaredConstructor(int.class,String.class);
constructor.setAccessible(true);
Person person=(Person) constructor.newInstance(25,"晓明");
System.out.println(person);
}

动态代理的使用场合:
①调试
②远程方法调用

静态代理:
public class TestProxy {
public static void main(String[] args) {
ProxyClothFactory proxyClothFactory=new ProxyClothFactory(new NikeClothFactory());
proxyClothFactory.productCloth();
}
}
interface ClothFactory{
void productCloth();
}
/*
 * 被代理类
 */
class NikeClothFactory implements ClothFactory{
@Override
public void productCloth() {
System.out.println("开始生产Nike衣服");
}
}
/*
 * 代理类
 */
class ProxyClothFactory  implements ClothFactory{
ClothFactory clothFactory;
public ProxyClothFactory(ClothFactory clothFactory) {
this.clothFactory=clothFactory;
// TODO Auto-generated constructor stub
}
@Override
public void productCloth() {
clothFactory.productCloth();
// TODO Auto-generated method stub
}
}

动态代理
public class TestProxy {
public static void main(String[] args) {
//1、创建被代理类的对象
RealSubject real=new RealSubject();
//2、创建了一个实现了InvocationHandler接口的类的对象
MyInvocationHandler handler=new MyInvocationHandler();
//3、调用blind()方法,动态的返回一个同样实现了real所在类实现的接口的Subject的代理类的对象。
Object obj=handler.blind(real);
Subject sub=(Subject) obj;//此时的sub就是代理类的对象
sub.action("晓明",25);//转到对InvocationHandler接口的invoke()方法的调用

//再举一例
NikeClothFactory nike=new NikeClothFactory();
ClothFactory proxyCloth=(ClothFactory) handler.blind(nike);
proxyCloth.productCloth();
}
}
//动态代理的使用,体会反射是动态语言的关键。
interface Subject{
void action(String name,int age);
}
//被代理类
class RealSubject implements Subject{
@Override
public void action(String name,int age) {
System.out.println(name+"的年龄是"+age+"岁");
}
}
//动态代理核心类
class MyInvocationHandler implements InvocationHandler{
Object obj;//实现了接口的被代理类的对象的声明
//①给被代理的对象实例化  ②返回一个代理类的对象
public Object blind(Object obj){
this.obj=obj;
//newProxyInstance方法三个参数分别为:
//①被代理类的类加载器;
//②被代理类实现的接口  
//③实现了InvocationHandler接口的实现类的对象

return Proxy.newProxyInstance(obj.getClass().getClassLoader(), 
obj.getClass().getInterfaces(),
this);
}
//当通过代理类的对象发起对被重写的方法的调用时,都会转化为对如下的invoke方法的调用。
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//proxy相当于代理类的实例对象,相当于main()方法中的sub.
//以下代码相当于执行被代理类的重写方法。
//method指被代理类的重写方法名(如RealSubject的action方法名称),obj是指被代理对象的实例(即RealSubject的实例对象)
//args是参数列表
Object returnVal=method.invoke(obj, args);
return returnVal;
}
}

interface ClothFactory{
void productCloth();
}
/*
 * 被代理类
 */
class NikeClothFactory implements ClothFactory{
@Override
public void productCloth() {
System.out.println("开始生产Nike衣服");
}
}
/*
 * 代理类,有了动态代理后,就不需要使用静态代理了。
 */
//class ProxyClothFactory  implements ClothFactory{
// ClothFactory clothFactory;
// public ProxyClothFactory(ClothFactory clothFactory) {
// this.clothFactory=clothFactory;
// // TODO Auto-generated constructor stub
// }
// @Override
// public void productCloth() {
// clothFactory.productCloth();
// // TODO Auto-generated method stub
// }
//}

网络编程:
通讯要素:
①IP和端口号(应用层)
②网络通信协议(传输层,包括TCP协议和UDP协议 TCP协议为TCP/IP协议的简称)

端口号与IP地址的组合得出一个网络套接字。
TCP:传输控制协议 IP:网络互联协议

如何创建一个InetAddress的对象?getByName("");
比如:InetAddress inet=InetAddress.getByName("192.168.0.1");

TCP的编程: Socket(套接字) ServerSocket
UDP的编程:DatagramSocket DatagramPacket
URL:统一资源定位符

网络通信其实就是socket的通信,数据在两个socket间通过IO传输。
一般主动发起通信的应用程序属客户端,等待通信请求的为服务端。

/*
* InetAddress用来代表IP地址。一个InetAddress的对象代表着一个IP地址。
*/
public static void main(String[] args) throws UnknownHostException {

InetAddress inet=InetAddress.getByName("www.atguigu.com");
// InetAddress inet=InetAddress.getByName("127.0.0.1");
System.out.println(inet);
System.out.println(inet.getHostName());//获取域名
System.out.println(inet.getHostAddress());//获取主机地址

InetAddress inetAddress=InetAddress.getLocalHost();//获取本机的IP
System.out.println(inetAddress);
System.out.println(inetAddress.getHostName());
System.out.println(inetAddress.getHostAddress());
}


/*
* 客户端给服务器发信息,服务器输出此信息到控制台上。
*/
@Test
public void Client(){
Socket socket=null;
OutputStream os=null;
try {
InetAddress inet=InetAddress.getByName("localhost");
socket = new Socket(inet, 9090);
os = socket.getOutputStream();
os.write("客户端发来的信息".getBytes());
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if (os!=null) {
try {
os.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (socket!=null) {
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
@Test
public void server(){
ServerSocket ss=null;
Socket s=null;
InputStream is=null;
try {
ss = new ServerSocket(8082);
s = ss.accept();
is = s.getInputStream();
byte[] b=new byte[1024];
int len;
StringBuffer sb = new StringBuffer();
while((len=is.read(b))!=-1){
sb.append(new String(b, 0, len));
}
System.out.println(sb);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if (is!=null) {
try {
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (s!=null) {
try {
s.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (ss!=null) {
try {
ss.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

/*
* 客户端给服务器发生信息,服务器将信息打印到控制台上,同时发生“服务器已经接到您的信息”给客户端。
*/
@Test
public void client(){
Socket socket=null;
OutputStream os=null;
InputStream is=null;
try {
InetAddress inet=InetAddress.getByName("localhost");
socket = new Socket(inet, 8989);
os = socket.getOutputStream();
os.write("您好,我是客户端,您收到信息后请给我回信息".getBytes());
//shutdownOutput()执行该方法显示地告诉服务器端已经发生完毕。
//由于服务器端发送完毕后刚回关闭资源,所以不用使用该方法。
socket.shutdownOutput();
is = socket.getInputStream();
byte[] b=new byte[1024];
int len;
StringBuffer sb=new StringBuffer();
while((len=is.read(b))!=-1){
sb.append(new String(b, 0, len));
}
System.out.println(sb);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if (is!=null) {
try {
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (os!=null) {
try {
os.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (socket!=null) {
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
@Test
public void server(){
ServerSocket ss=null;
Socket s=null;
InputStream is=null;
OutputStream os=null;
try {
ss = new ServerSocket(8989);
s = ss.accept();//服务器端的Socket对象是通过ServerSocket对象的accept()方法获取。
is = s.getInputStream();
byte[] b=new byte[1024];
int len;
StringBuffer sb=new StringBuffer();
while((len=is.read(b))!=-1){
sb.append(new String(b,0,len));
}
System.out.println(sb);
os = s.getOutputStream();
os.write("服务器已经接到您的信息".getBytes());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if (os!=null) {
try {
os.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (is!=null) {
try {
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (s!=null) {
try {
s.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (ss!=null) {
try {
ss.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

类DatagramSocket和DatagramPacket实现了基于UDP协议网络程序。
UDP数据报通过数据报套接字DatagramSocket发送和接收,系统不保证UDP数据报一定能够安全送到目的地,也不能确定什么时候开业抵达。
DatagramPacket对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号。
每个数据包的大小不大于64K

URL编程:
URL:统一资源定位符,一个URL的对象,对应着互联网上一个资源。
我们可以通过URL的对象调用其相应的方法,将此资源读取。
URL url=new URL("http://fanyi.baidu.com/?aldtype=85#en/zh/datagram");
//如何将服务器的资源读取进来:openStream()
InputStream is = url.openStream();
byte[] b=new byte[1024];
int len;
while((len=is.read(b))!=-1){
System.out.print(new String(b, 0, len, "utf-8"));
}
//如果既有数据的输入,又有数据的输出,则考虑使用URLConnection
URLConnection urlconn=url.openConnection();






 

























  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值