------- android培训、java培训、期待与您交流! ----------
>>面向对象是基于面向过程的。
特征:封装
>>成员变量作用于整个类中,局部变量作用于函数中,或者语句中。
成员变量存放在堆内存中,因为对象的存在,才在内存中存在。
局部变量存在栈内存中。
>>匿名对象当对对象的方法只调用一次时,可以用匿名对象完成,这样比较简化。如果对一个对象进行多个成员调用,必须给这个对象取个名字。
可以将匿名对象作为实际参数进行传递。
eg:show(new Car());
public static void show(Car c)
{
c.num = 3;
c.color = “black”;
c.run();
}//注意,运行后show释放。
如果newCar().num = 5;运行后,匿名对象成为垃圾。
>>封装(Encapsulation)是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
函数就是JAVA中最小的封装。类也是封装。
>>private封装实例,注意,私有仅仅是封装的一种表现形式。
eg:class Person
{
private int age;
void speak();
{
System.out.println(“age=”+age);
}
}
classPersonDemo
{
public static voidmain(String[] args)
{
Person p = new Person();
//p.age = -20;//私有化后,age不能访问了
p.speak();
}
}
怎么访问age呢?在Person类中提供两个方法
public voidsetAge(int a)
{age=a;}
以及
public intgetAge()
{return age;}。
把属性都隐藏,提供公共方法对其访问。
>>构造函数的名字与类名相同,不需要定义返回值类型(注意,连void都不用,不用return语句)不论有几个构造函数(可以定义参数不同的构造函数),名字必须与类名相同。
对象一建立就会调用与之对应的构造函数。(而一般方法是对象调用才执行,是给对象添加对象具备的功能,对象建立,构造函数只运行一次,而一般方法可以反复调用)
构造函数的作用:可以用于给对象进行初始化。
当一个类中没有定义构造函数时,那么系统会默认给该类加入一个空参数的构造函数。但是当类中自定义了构造函数后,默认的构造函数就没有了。
构造函数也是成员,也可以被私有化,但一般不这样做。类中所有的构造函数初始化就创建不了对象
>>构造代码块。
作用:给对象进行初始化。
对象一建立就运行。注意:优先于构造函数执行。
和构造函数的区别:
构造代码块是给“所有”对象进行统一初始化,
而构造函数是给“对应”的对象初始化!!!
构造代码块中定义的是不同对象共性的初始化内容。
eg:
class Person
{
privateString name;
privateint age;
{
//System.out.println("personcode run");//构造代码块。
cry();
}
Person()
{
System.out.println("A:name="+name+",,age="+age);
}
……………………
>>如果这样定义构造函数
Person(String name)
{
name= name;
}//则局部变量给局部变量赋值,而不是赋给成员变量。
Person(String name)
{
this.name= name;//this用于区分局部变量与成员变量同名的情况。
}
this代表本类对象,this代表它所在函数所属对象的引用。
类中成员互相调用其实都是对象在执行。
>>eg:this应用,比较年龄
publicboolean compare(Person p)
{
returnthis.age==p.age;
}
class PersonDemo3
{
publicstatic void main(String[] args)
{
Personp1 = new Person(20);
Personp2 = new Person(25);
booleanb = p1.compare(p2);//传入p2
System.out.println(b);
}
}
>>this构造函数间调用
Person(String name,int age)
{//this.name = name;
this(name);//调用构造函数person(String name)
this.age= age;
}
构造函数之间调用只能用this,注意只能放在构造函数的第一行(第一个语句),因为初始化要先执行。
>>eg:
Person()
{
this("haha");
}
Person(Stringname)
{
this();
}
注意,调用死循环
>>静态修饰的成员不在堆内存中,而在方法区(或叫共享区、数据区)中。
当成员被静态修饰后,就多了一个调用方式,除了可以被对象调用外,还可以直接被类名调用(类名.静态成员)。
>>static特点:
1) 随着类的加载而加载。
2) 优先于对象存在!!!!!
3) 被所有对象所共享。
4) 可以直接被类名调用。
eg:class Person
{
String name;//成员变量,实例变量。对象存在才存在。
static Stringcountry = “cn”;//静态的成员变量,类变量。
}
实例变量和类变量的区别:
1, 存放位置:类变量随着类的加载而存在与方法区中。实例变量随着对象的简历而存在与堆内存中。
2, 生命周期:类变量生命周期最长,随着类的消失而消失。实例变量生命周期最长,随着类的随着类的消失而消失,生命周期最长。
>>静态使用注意事项:
1、 静态方法只能访问静态成员。非静态方法既可以访问静态也可以访问非静态。
2、 静态方法中不可以定义this,super关键字,因为静态优先于对象存在,所以静态方法中不可以出现this。
>>关于主函数public staticvoid main(String[] args)
主函数:是一个特殊的函数。作为程序的入口,可以被虚拟机调用。
主函数的定义:
public:代表着该函数访问权限是最大的。
static:代表主函数随着类的加载就已经存在了。
void:主函数没有具体的返回值。
main:不是关键字!但是是一个特殊的单词,可以被虚拟机识别。
(String[] args):函数的参数,参数类型是一个数组,该数组中的元素是字符串。字符串类型的数组。
主函数是固定格式的:虚拟机识别。即如果有这样的代码:
class MainDemo
{
publicstatic void main(String[] args){}
publicstatic void main(int x){}
}
是可以的,这是重载,但是虚拟机固定先调用public static void main(String[] args){}!!
虚拟机在调用主函数时,传入的是new String[0];注意是零个元素。
主函数中唯一能改动的:args
(花边:args当年写的是arguments)
>>java命令启动的是底层的虚拟机,所以可以存入数据。
eg:传入命令java MainDemoone two three
输出:System.out.println(args[0]);输出“one”。
>>因为类名可以调用静态方法,所以可以在其它类调用主函数
eg:String[] arr= {“one”,”two”,”three”};
MainTest.main(arr);
>>什么时候使用静态?
两个方面:静态修饰的内容有成员变量和函数
1)什么时候定义静态变量(类变量)呢?
当对象中出现共享数据(注意不是共享属性,大学是属性,人民大学是数据)时,该数据被静态所修饰。对象中得特有数据要定义成非静态存在于对堆内存中。
2)什么时候定义静态函数呢?
当功能内部没有访问到非静态数据(对象特有数据,比如String name;),那么该功能可以定义成静态的。
>>编译一个类,如果这个类中调用了另一个类,编译器会在制定目录(classpath)或当前目录查找调用的类“**.java”并编译成“.class”文件。(被调用的类要有.java文件或.class文件,否则编译错误)
>>技巧:定义一个“工具”类,将其中的功能函数(比如取最大值、最小值、排序等)定义成静态函数,用类直接调用,不必建立对象。为了更严谨,不让这个类建立对象,可以私有化该类的构造函数。
>>制作帮助文档(API文档:applicationprogram interface),向类的使用者说明类中的功能
eg:
/**
这是一个可以对……进行操作的工具类……该类中提供了…………功能。
@author douglas(@可以被识别)
@version v1.1
*/
class ArrayTool
{
public static int getMax(int[] arr)
/**
@param arr 接收一个int类型的文档
@return 会返回一个数组中得最大值
*/
public static int……………………
……………………………………
生成文档:javadoc –dc:\helpdoc –author –version ***.java
如果没有写路径而只写helpdoc,会在当前目录下新建目录helpdoc。
“–author –version”可选。
注意:能生成帮助文档的只能是public类且其中的私有方法不能体现,构造函数要体现也要添加public。(一个类中默认会有一个空参数的构造函数,这个默认的构造函数的权限和所属类一致,即如果类被public修饰,默认的构造函数也也带public修饰符,反之亦然)
>>静态代码块
static
{
执行语句;
}//随着类的加载而执行,只执行一次,用于给类初始化。
eg:class StaticCode{
System.out.println(“a”);
}
classStaticCodeDemo
{
static
{
System.out.println(“b”);
}
publicstatic void main(String[] args)
{
newStaticCode();
newStaticCode();//类StaticCode已经加载进内存,不会输出两个a;
System.out.println(“over”);
}
static
{
Systme.out.println(“c”);
}
}//输出结果b c a over。//类StaticCode已经加载进内存,不会输出两个a;
又,有如此语句:StaticCode s = null;不会输出a,这个时候类StaticCode根本不会加载。
注意,静态代码块不能调用非静态变量。
>>重要!!
对象初始化Person p = new Person(“zhansan”,20);
该句话都做了什么事情?
1,因为new用到了Person.class.所以会先找到Person.class文件并加载到内存中。
2,执行该类中的static代码块,如果有的话,给Person.class类进行初始化。
3,在堆内存中开辟空间,分配内存地址。
4,在堆内存中建立对象的特有属性。并进行默认初始化。
5,对属性进行显示初始化。(比如intage = 20;)
6,对对象进行构造代码块初始化。
7,对对象进行对应的构造函数初始化。
8,将内存地址付给栈内存中的p变量。
>>设计模式:解决某一类问题行之有效的方法。
JAVA中有23种设计模式;
单例设计模式:解决一个类在内存只存在一个对象。
思想:1、为了避免其它程序过多建立对象,先禁止其它程序建立该对象。
2、还为了其他程序可以访问到该类对象,只好在本类中,自定义一个对象。
3、为了方便其它程序对自定义对象的访问,可以对外提供一些访问方式。
体现:1、构造函数私有化。
2、在类中创建一个本类对象。
3、提供一个方法可以获取到该对象。
eg:class Single
{
private Single(){}
private static Single s = newSingle;//注意静态
prblic static Single getInstance()//注意静态
{
return s;
}
classSingleDemo
{
public stati voidmain(String[] args)
{
Single s1 =Single.getInstance();
Single s2 =Single.getInstance();
//s1、s2指向同一个对象
}
}
>>两个方式
饿汉式。:Single类一进内存,就已经创建好了对象。
classSingle
{
private static Single s = new Single();
private Single(){}
public static Single getInstance()
{
return s;
}
}
懒汉式:对象是方法被调用时,才初始化,也叫做对象的延时加载。。
//Single类进内存,对象还没有存在,只有调用了getInstance方法时,才建立对象。
classSingle
{
private static Single s = null;
private Single(){}
public static Single getInstance() //publicstatic synchronized Single getInstance()这样效率低
{
if(s==null)
{
synchronized(Single.class)//效率解决方案
{
if(s==null)
s= new Single();
}
}
return s;
}
}
//定义单例,建议使用饿汉式。如果多人调用懒汉式,会出现问题,在
if(s==null)
s= new Single();中
,CPU的切换会造成对象不唯一。解决方法“synchronized”同步。
>>继承
class 子类 extends 父类
1、提高代码的复用性。
2、让类与类之间产生了关系,有了这个关系,才有了多态的特性。
>>java中只支持单继承,不支持多继承,多继承带来安全隐患。
eg:class A{
void show(){System.out.println(“a”);}
}
class B{
void show(){System.out.println(“b”);}
}
class C extends A,B //假设可以多继承
{}
问题来了C c = new C();
c.show();//输出什么,结果是不确定。
但是java保留了这种机制,并用“多实现”的形式来体现。
>>另外,可以多层继承,也就是一个继承体系。
想要使用体系,先查阅体系父类的描述,因为父类定义了共性的功能。通过了解共性的功能,就可以基本了解该体系的基本功能。
调用时,要创建最子类的对象,因为父类可能不能创建对象,且创建子类对象可以使用更多的功能,包括基本和特有的。
>>父类和子类有相同非私有成员变量(比如int num),打印子类的变量num(this.num),要打印父类的num,这样:super.num,因为父类也叫超类。
当父类中有int num时,子类中,this.num和super.num功能相同,可以理解为指向同一个对象。
>>父类的构造函数比子类先调用,原因是有默认(隐藏)语句super();在子类每个构造函数的第一行。会访问父类中空参数的构造函数。所以,父类中如果没有空参数构造函数,子类中有super();通不过编译,但是可以这样super(4);与父类构造函数参数相同即可。
因为父类中的数据子类可以直接获取。所以子类对象在建立时,需要先查看父类是如何对这些数据进行初始化的。所以子类在对象初始化时,要先访问一下父类中的构造函数。
特殊情况:
eg:class Zi extends Fu
{
Zi()
{
//this();不能通过编译,子类中至少一个构造函数访问父类
super();
System.out.println("zirun");
}
Zi(int x)
{
this();
System.out.println("zi..."+x);
}
}
说明:
1、子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。子类中至少会有一个构造函数会访问父类中的构造函数。
2、super();this();都要放在第一行,所以有了this();语句,这个构造函数就没有super();了。放第一行是因为初始化动作要先做。
其实父类的构造函数中也有super();原因是java中有一个所有类的父类Object!
>> final :作为一个修饰符,特点:
1、可以修饰类,函数,变量。
2、被final修饰的类不可以被继承。继承的弊端是打破了封装性。为了避免被继承,被子类覆盖方法。
3、被final修饰的方法不可以被复写。
4、被final修饰的变量是一个常量!只能赋值一次,既可以修饰成员变量,有可以修饰局部变量。当在描述事物时,一些数据的出现值是固定的,那么这时为了增强阅读性,都给这些值起个名字。方便于阅读。而这个值不需要改变,所以加上final修饰。作为常量:常量的书写规范所有字母都大写,如果由多个单词组成:单词间通过_连接。
5,内部类定义在类中的局部位置上是,只能访问该局部被final修饰的局部变量。
>>abstract抽象方法一定要存放在抽象类中
eg:abstract class Student
{
abstract void study();
}
抽象类不可以用new创建对象,因为调用抽象方法没有意义。要使用抽象类中的方法,必须由子类复写其所有抽象方法后,建立子类对象调用。注意,如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类。
抽象类中也可以由非抽象方法。抽象类和一般类没有太大不同。只不过多了抽象函数,描述的一些事物中有一些不确定的部分,这些部分也是该事物的功能,需要明确出现,但是无法定义实体。
注意,abstract抽象修饰类和方法,不修饰变量,抽象类中可以不定义抽象方法。
>>小程序eg:
//System.currentTimeMillis();返回以毫秒为单位的当前时间。
abstractclass GetTime
{
public final void getTime()//禁止复写
{
long start =System.currentTimeMillis();
runcode();
long end =System.currentTimeMillis();
System.out.println("毫秒:"+(end-start));
}
public abstract void runcode();
}
classSubTime extends GetTime
{
public void runcode()
{
for(int x=0; x<4000; x++)
{
System.out.print(x);
}
}
}
class TemplateDemo
{
public static void main(String[] args)
{
SubTime gt = new SubTime();
gt.getTime();//注意,调用的是“getTime();”其中的“runcord();”已经被复写
}
}
这个小程序说明的是模板方法设计模式:在定义功能时,功能的一部分是确定的,但是有一部分是不确定,而确定的部分在使用不确定的部分,那么这时就将不确定的部分暴露出去。由该类的子类去完成。
>>接口:interface,其中全部方法是抽象方法。所以接口也不可以创建对象,其子类需要对接口中得抽象方法全都覆盖。
接口是向外暴露的规则。
降低了耦合性。
>>接口中定义常量和方法,即使没有写全,系统也会自动加上的代码:
public static final int NUM = 3;//可以不写public static final,int不能省略
public abstract void show();//可以不写public abstract,void不能省略
当然,为了可阅读性,还是写上为好。此也为接口中变量和方法的固定格式。
>>接口和所谓“子类”就不是继承关系,而是实现关系了—implements!
eg:interface Inter
{
public static final int NUM =3;
publicabstract void show();
}
class Test implements Inter
{
public void show();
}
class InterfaceDemo
{
publicstatic void main(String[] args)
{
Test t = new Test();
System.out.println(t.NUM); //合法的
System.out.println(Test.NUM); //合法的
System.out.println(Inter.NUM);//合法的
//t.NUM = 4;//注意,不合法的
}
}
>>接口可以被类多实现,原因是接口中也有可能会有重复的方法,但是方法都没有方法体,可以由子类重复定义。
eg:class Test implementsInterA,InterB{}
而且,还可以继承后实现多个接口
class Test extends Demo inplementsInterA,InterB{}
>>类于类之间是继承关系;类与接口之间是实现关系;接口与接口之间是继承关系,而且可以多继承。
>>重载和覆盖就是函数多态性的体现。
>>多态在程序中的体现,父类的引用指向了自己的子类对象,且父类的引用也可以接收自己的子类对象。
eg:
abstractclass Animal
{
abstract void eat();
}
class Catextends Animal
{
public void eat()
{
System.out.println("吃鱼");
}
public void catchMouse()
{
System.out.println("抓老鼠");
}
}
publicstatic void main(String[] args)
{
//Animal c = new Cat(); //Cat c = new Cat();类型提升,向上转型
//c.eat();
function(new Cat()); //调用封装方法
}
//将吃的方法封装,如果这样写:
/*publicstatic void function(Cat c)//如果要定义Dog,那么还要重写代码,造成重复
{
c.eat();
}
public static void function(Dog d)
{
d.eat();
}
*/
//所以可以这样:
publicstatic void function(Animal a)//Animal a = new Cat();
{
a.eat();
}
>>多态的前提:必须是类与类之间有关系。要么继承,要么实现。且通常还有一个前提:存在覆盖。
>>多态的好处:多态的出现大大的提高程序的扩展性。
多态的弊端:提高了扩展性,但是只能使用父类的引用访问父类中的成员。
>>eg:
classDuoTaiDemo2
{
public static void main()
{
Animal a = new Cat();//类型提升,向上转型。
a.eat();
Cat c = (Cat)a;//强制将父类的引用转换成子类类型,向下转型。
c.catchMouse();//而后可以调用猫的特有方法
//千万不要出现这样的操作,就是将父类对象转成子类类型。
//Animal a = new Animal();
//Cat c = (Cat)a;
//我们能转换的是父类应用指向了自己的子类对象时,该应用可以被提升,也可以被强制转换。
//多态自始至终都是子类对象在做着变化。
>>eg:判断基本数据类型使用if(a==0),如果是判断类?
使用instanceof : 用于判断对象的类型。 对象 intanceof 类型(类类型 接口类型)
publicstatic void function(Animal a)
{
a.eat();
/*
不要这样判断,因为无论传什么都符合父类
if(a instanceof Animal)
{
System.out.println("haha");
}
else
*/
if(a instanceof Cat)
{
Cat c = (Cat)a;
c.catchMouse();
}
else if(a instanceof Dog)
{
Dog c = (Dog)a;
c.kanJia();
}
>>eg:
……//其中子类对method1()方法进行了复写,父类没有method3()方法
fu f = new zi();//编译看左边,运行看右边
f.method1();//输出的是子类中的内容
f.method2();//输出的是父类中的内容
f.method3();//造成编译错误
……
在多态中成员函数的特点:
在编译时期:参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过否则失败。在运行时期:参阅对象所属的类中是否有调用的方法。
简单来说,成员函数在多态调用时,编译看左边,运行看右边
>>面试环节
eg:父类中定义num = 5,子类中定义num = 8;
……
Fu f =new Zi();
System.out.println(f.num);
Zi z =new Zi();
System.out.println(z.num);
……
输出58
注意:在多态中,成员变量的特点:无论编译和运行,都参考左边(引用型变量所属的类)。
>>面试环节:
多态成员函数是非静态的,如果有以下情况:
eg:class Fu
{
static void method4()
{
System.out.println("fumethod_4");
}
}
class Ziextends Fu
{
static void method4()
{
System.out.println("zimethod_4");
}
}
publicstatic void main(String[] args)
{
Fu f = new Zi();
f.method4();
Zi z = new Zi();
z.method4();
}
输出的是:fu method_4
zi method_4
多态中,静态成员函数的特点,无论编译和运行,都参考左边
静态绑定,静态方法调入内存,即绑定在其所属的类上。
动态绑定,对象是谁的,就运行谁的方法
>>object:根类,有所有对象共有的方法。
eg:equals()比较两个对象是否相等
Demo one= new Demo();
Demo two= new Demo();
Demothree = one;
System.out.println(one.equals(two));
System.out.println(one==two);
System.out.println(one==three);
//输出: false
false
true
证明比较的是内存空间
eg:toString()输出对象的字符串表示
Demo d1 =new Demo(4);
System.out.println(d1.toString());//输出d1的哈希值
注意,一般toString(),equals(),hashCode()这些方法都会被复写下,因为object类带的方法输出意义不大。
>>访问内部类中的成员
eg://因为可能还有Outer2类,其中也有一个Inner类。
Outer.Inner in = new Outer().new Inner();//只是一种格式
in.function();
>>三个同名成员,想打印3怎么办
classOuter
{
private int x = 3;//外部成员
class Inner//内部类
{
int x = 4;//内部成员
void function()
{
int x = 6;//内部局部成员
System.out.println("innner:"+Outer.this.x);//Outer.this标志此this是Outer的;如果只有this,则打印4。
}
}
//x前面省略了什么
classOuter
{
//private int x = 3;//外部成员
class Inner//内部类
{
//int x = 4;//内部成员
void function()
{
int x = 6;//内部局部成员
System.out.println("innner:"+ x);// x前面省略了“Outer.this.”这时打印3。
}
}
这就是内部类能直接访问外部类成员的原因。且包括私有成员。
外部类要访问内部类,必须建立内部类对象。
>>内部类变成静态时,就具备了静态的特性。
eg:private int x = 3;
static class Inner
{
voidfunction()
{
System.out.println(x);
}
}//编译错误,无法访问非静态成员,内部类被static修饰后,只能访问外部类中的静态成员,出现了访问局限。
外部类如何访问静态内部类中的非静态成员?这样:new Outer.Inner().function();
外部类如何访问静态内部类中的静态成员?这样Outer.Inner.function();
注意:当内部类中定义了静态成员,该内部类必须是静态的。
当外部类中的静态方法方法访问内部类时,内部类也必须是静态的。
>>局部内部类(比如外部类方法中定义的一个类)不能被静态修饰,所以该类内部的成员也不能是静态的。
内部类可以直接访问外部类中的成员,因为还持有外部类中的引用,但是不可以访问他所在的局部中的变量,只能访问被final修饰的局部变量。
eg:
classOuter
{
int x = 3;
void method(final int a)//栈内存中有a
{
//++a;//这样,编译错误
final int y = 4;
class Inner
{
void function()
{
System.out.println(y);//final int y
}
}
new Inner().function();
}
}
class InnerClassDemo3
{
public static void main(String[] args)
{
Outer out = new Outer();
out.method(7); //out.method(7);执行完,出栈!
out.method(8);// out.method(8);入栈,所以即使是final也没有错误。
}
}
>>匿名内部类
1、匿名内部类其实就是内部类的简写格式
2、定义匿名内部类的前提:
内部类必须是继承一个类或者实现接口。
3、匿名内部类的格式: new 父类或者接口(){定义子类的内容}
4、其实匿名内部类就是一个匿名子类对象。而且这个对象有点胖。可以理解为带内容的对象。
5、匿名内部类中定义的方法最好不要超过3个。因为当父类中得抽象方法过多,创造的匿名内部类阅读性很差
eg:abstract class AbsDemo
{
abstract void show();
}
classOuter
{
/*
class Inner extends AbsDemo
{
int num = 90;
void show()
{
System.out.println("show:"+num);
}
void abc()
{
System.out.println("hehe");
}
}
*/注释部分的简化写法(以下代码)就是匿名内部类,且为AbsDemo的子类对象
public void function()
{
new AbsDemo()//注意不能加“;”
{
void show()
{
System.out.println(“x=”+x);
}//这是复写方法
void abc()
{
System.out.println(“abc”)
}//这是子类特有方法
}.show();//可以理解成new Inner.show();,另外,只能调用show()或abc()方法
}
}
>>匿名内部类的局限性
eg:AbsDemo d = new AbsDemo()//如果这样书写
{
void show()
{
System.out.println(“x=”+x);
}//这是复写方法
void abc()
{
System.out.println(“abc”)
}//这是子类特有方法
};
d.show();//通过
d.abc();//便以失败
匿名内部类就是为了简化书写。
>>eg:匿名对象举例,要求补足代码,通过匿名对象
interfaceInter
{
void method();
}
classTest
{
}
classInnerClassTest
{
public static void main(String[] args)
{
Test.function().method();
}
}
Test.function().method();//分析这句话,知道有一个Test类中有一个function()方法,且Test后跟“.”证明function()还是静态方法。还有,function()后面又跟了一个“.method()”,说明function()方法运算的结果是一个对象。对象才能调用method()方法。所以,是Inter的对象。也就是说这句话可以这样看:
Inter in= Test.function();
in.methot();
所以,补足的代码为
staticclass Inner implements Inter
{
public void method()
{
Systme.out.println(“methodrun”);
}
}
staticInter function()
{
return new Inner();
}
需要变成内部类,则补充代码为:
staticInter function()
{
return new Inter()//返回匿名内部类
{
public void method()
{
Systme.out.println(“methodrun”);
}
}
}
>>匿名内部类可以作为参数传给方法
eg:show(new Inter()
{
public void method()
{
Systme.out.println(“xx”);
}
}
);//要特别注意括号顺序
>>如果没有父类也没有接口,能建立匿名内部类么?
可以,因为还有object类(所有类的父类)
eg:public static void main(String[]args)
{
new object()
{
public voidfunction()
{
}
}.function();
}
>>异常是程序在运行时(注意不是编译时)出现不正常情况。
对于严重的,java通过Error类进行描述。对于此类一般不编写针对性的代码对其进行处理。
对于非严重的,java通过Exception类进行描述。对于此类可以使用针对性的处理方式进行处理。
Error与Exception有一些共性,它们向上抽取的父类是Throwable。
java提供了特有的语句进行异常处理,格式:
try
{
需要被检测的代码;
}
catch(异常类 变量)
{
处理异常的代码;(处理方式)
}
finally
{
一定会执行的语句;
}
>>错误处理过程:
eg:class Demo
{
intdiv(int a,int b)
{
returna/b;
//java虚拟机识别的算术问题,产生问题被封装成对象:new AritchmeticException()
}
}
class ExceptionDemo
{
publicstatic void main(String[] args)
{
Demod = new Demo();
try
{
intx = d.div(4,1);// new AritchmeticException()被try检测到后丢给catch
System.out.println("x="+x);//上一句跳转了,所以此句不执行了
}
//catch怎么接呢?这样
catch(Exception e) //Exception e = new ArithmeticException();
{
System.out.println("除零啦");
System.out.println(e.getMessage());//返回throwable的详细消息字符串
System.out.println(e.toString());//异常名称;异常信息
e.printStackTrace();//打印异常名称,异常信息,异常出现位置。
//其实虚拟机默认的异常处理机制,就是在调用printStackTrace方法打印异常的堆栈的跟踪信息。
}
System.out.println("over");
}
}
>>eg: int div(int a,int b)throws Exception
在功能上通过throws的关键字声明了该功能有可能会出现问题。把问题抛给调用者。
>>多异常处理
eg:int div(int a,int b)throwsArithmeticException,ArrayIndexOutOfBoundsException
//算术异常和数组异常
{
int[] arr = new int[a];
System.out.println(arr[4]);//注意,这里一越界,a/b便不运算了。
return a/b;
}
………………
try
{
int x = d.div(4,0);//传入有问题的数据
System.out.println("x="+x);
}
/*catch(Exception e)//使用这个可以处理,因为多态性,但是没有针对性
{
System.out.println("hahah:"+e.toString());
}*/
catch (ArithmeticException e)//算术错误
{
System.out.println(e.toString());
System.out.println("被零除了!!");
}
catch(ArrayIndexOutOfBoundsException e)//数组角标越界
{
System.out.println(e.toString());
System.out.println("角标越界啦!!");
}
那么,如果发生除算术和数组异常外的异常呢?
所以,1,声明异常时,建议声明更为具体的异常。这样处理的可以更具体。2,对方声明几个异常,就对应有几个catch块。不要定义多余的catch块。如果多个catch块中的异常出现继承关系,父类异常catch块放在最下面。
建立在进行catch处理时,catch中一定要定义具体处理方式。不要简单定义一句 e.printStackTrace(),也不要简单的就书写一条输出语句。
>>自定义异常
我们自定义一个异常,假设除数是负数也是异常
eg:class FuShuException extendsException//继承了Exception才算作进入异常的“体系”
{
privateint value;
FuShuException(String msg,intvalue)//同时返回异常值
{
super(msg);
this value = value
}
int getValue()
{
returnvalue;
}
}
class Demo
{
int div(int a,int b)throwsFuShuException//函数内出现异常,函数上要声明
{
if(b<0)
throw newFuShuException("出现了除数是负数的情况------ / by fushu",b);
//手动通过throw关键字抛出一个自定义异常对象。
return a/b;
}
}
class ExceptionDemo
{
public static void main(String[] args)
{
Demo d = new Demo();
try
{
int x = d.div(4,-9);
System.out.println("x="+x);
}
catch (FuShuException e)
{
System.out.println(e.toString());
System.out.println("错误的负数是:"+e.getValue());//得到错误的数
}
System.out.println("over");
}
}
>>throws和throw的区别
1、throws使用在函数上,而throw使用在函数内。
2、throws后面跟的异常类,可以跟多个,用逗号隔开,而throw后跟的是异常对象。
>>函数内抛,函数上一定要标示,否则编译失败,但是有一个特例:RuntimeException,其是Exception的子类,其在函数内抛出,函数上不用声明编译可以通过。又其在函数上声明时,调用者可以不用进行处理(抛出或try),编译可以通过。
自定义异常时:如果该异常的发生,无法在继续进行运算,就让自定义异常继承RuntimeException。
eg:class Demo
{
int div(int a,int b)throws Exception
{
if(b==0)
throw newArithmeticException("被零除啦");//RuntimeException子类
return a/b;
}
}
之所以不用在函数声明,是因为不需要让调用者处理。当该异常发生,希望程序停止。因为在运行时,出现了无法继续运算的情况,希望停止程序后,对代码进行修正。
>>eg:class Person
{
public void checkName(String name)//如果name传null会错误,怎么办?
{
//if(name.equals("lisi"))//NullPointerException
if("lisi".equals(name))//解决方案,相当于if(name!=null &&name.equals("lisi"))
System.out.println("YES");
else
System.out.println("no");
}
}
对于异常分两种:
1、编译时被检测的异常。
2、编译时不被检测的异常(运行时异常,就是RuntimeException以及它的子类)
>>eg:需求:毕老师用电脑上课(创建类,名字提炼法)
问题:(对问题进行描述,封装对象)
电脑蓝屏,重新启动。
电脑冒烟,课时计划无法完成。
class LanPingException extendsException//电脑蓝屏,注意继承重要
{
LanPingException(Stringmessage)
{
super(message);
}
}
class MaoYanException extendsException//电脑冒烟
{
MaoYanException(Stringmessage)
{
super(message);
}
}
class NoPlanException extendsException
{
NoPlanException(Stringmsg)
{
super(msg);
}
}
class Computer
{
privateint state = 1;
publicvoid run()throws LanPingException,MaoYanException//标示
{
if(state==2)
thrownew LanPingException("蓝屏了");
if(state==3)
thrownew MaoYanException("冒烟了");
System.out.println("电脑运行");
}
publicvoid reset()
{
state= 1;//重新启动后恢复状态
System.out.println("重新启动");
}
}
class Teacher
{
privateString name;
privateComputer comput;
Teacher(Stringname)
{
this.name= name;
comput= new Computer();
}
publicString getName()
{
returnname;
}
publicvoid prelect()throws NoPlanException//标示
{
try
{
comput.run();
}
catch(LanPingExceptione)
{
comput.reset();
}
catch(MaoYanExceptione)//冒烟没法处理,抛出给主管处理
{
test();
//throwe;//抛出没有处理,注意标示
thrownew NoPlanException("课时无法继续"+e.getMessage());
//课程计划受到影响
//test();//抛出,这里的函数无法执行到
}
System.out.println("讲课");
}
publicvoid test()
{
System.out.println("做练习");
}
}
class ExceptionTest
{
publicstatic void main(String[] args)
{
Teachert = new Teacher("毕老师");
System.out.println(t.getName());
try
{
t.prelect();
}
catch(NoPlanExceptione)
{
System.out.println(e.toString());
System.out.println("换老师或者放假");//主管处理
}
}
}
>>finally中存放的是一定会被执行的代码
eg:
try
{……;}
catch
{
……;
return;//注意这个,程序在这里结束
}
finally
{
System.out.println(“finally”);//但是finally还是会执行
}
使用情况举例,比如操作数据库首先连接数据库,因为最后一定要断开以节省资源,所以一旦出问题,则
try{
连接数据库;
数据操作;//throw new SQLException()
}
catch(SQLExceptione){
……;// 数据库异常处理方式
}
//这时程序结束,但是没有释放连接,所以加上
finally{
关闭数据库;
}
//以释放资源。
注意:finally有一种情况不会被执行
当执行到System.exit(0);//系统(不是win或linux),退出,jvm结束
>>异常-处理语句格式
1、try+catch
eg:try{
throw newException();
}
catch{
……;
}//编译通过,有catch,代表问题解决
——————————————
try{
throw newException();
}
catch(Exception e){
throw e;
}//编译失败,问题被丢出
——————————————
try{
throw newException();
}
catch(Exception e){
try{
throw e;
}
catch(){
}
}//编译通过,问题被处理
2、try+catch+finally
3、try+finally
eg:try
{
throw new Exception();
}
finally//只是起到诸如释放资源的作用,没有处理问题
{
}//编译失败,没有catch,问题没有被处理
4、不可以只有try。catch用于处理异常,没有catch代表异常没有被处理,如果给异常是检测时异常,那么必须声明。
>>eg:异常在方法覆盖中
classAException extends Exception{}
classBException extends AException{}//B异常继承A异常
classCException extends Exception{}
class Fu
{
void show()throws AException{}//注意这里的抛出
}
class Ziextends Fu
{
void show()throws AException{}//要么不抛异常,要抛只能是A或B异常
}//不能抛C异常,通俗来讲子类只能有父类的问题,不能比父类有问题
……//对此解释,如果子类抛C异常,有方法function
voidfunction(Fu f)
{
try
{
f.show();
}
catch(AException e)//所谓“旧程序”,如果子类抛出C异常,运行的是
//voidshow() throws CException
{
……
}
}
…………
publicstatic void main(String[] args)
{
Test t = new Test();
t.function(new Zi());//导致旧程序无法处理新问题
}
>>如果父类方法抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子集。
如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常。也就是说如果子类发生C类异常,则只能在内部处理,不能抛出。
>>throw单独存在时,下面不要有语句,否则执行不到。
>>包的作用:对类文件进行分类管理,给类提供多层命名空间,运行文件与源文件分离
包需要写在程序文件第一行
类名的全称的是:包名.类名
eg:package pack;//包的关键字和包名
包也是一种封装形式
编译的时候的参数(自动生成包目录):
javac –dd:\workspace PackageDemo.java(-d directory)
javac –d. PackageDemo.java(“.”代表当前目录,注意前后空格)
运行:
javaprck.PackageDemo
不要忘了,如果class存到另一个文件夹,可以这样:
setclasspath=c:\myclass
>>包之间的访问
eg:package packa;
public classDemoA //错误3,需要权限
{
public void show()//错误4,需要权限
{
System.out.println("demoashow run");
}
}
————————————//错误2,需要设置classpath
packagepack;
class PackageDemo
{
public static void main(String[] args)
{
packa.DemoA d = newpacka.DemoA();//错误1
d.show();
}
}
一系列错误:
1、————————————————————————————————
PackageDemo.java:8:找不到符号
符号: 类 DemoA
位置: 类 pack.PackageDemo
DemoA d = new DemoA();
^
PackageDemo.java:8:找不到符号
符号: 类 DemoA
位置: 类 pack.PackageDemo
DemoA d = new DemoA();
^
2 错误
错误原因:类名写错。
因为类名的全名是:包名.类名
2、————————————————————————————————
PackageDemo.java:8:软件包 packa 不存在
packa.DemoA d = newpacka.DemoA();
^
PackageDemo.java:8:软件包 packa 不存在
packa.DemoA d = newpacka.DemoA();
^
2 错误
错误原因:packa包不在当前目录下
需要设置classpath,告诉jvm去哪里找指定的packa包。
3、————————————————————————————————
PackageDemo.java:8:packa.DemoA 在 packa 中不是公共的;无法从外部软件包中对其进
行访问
packa.DemoA d = newpacka.DemoA();
^
PackageDemo.java:8:packa.DemoA 在 packa 中不是公共的;无法从外部软件包中对其进
行访问
packa.DemoA d = newpacka.DemoA();
^
2 错误
错误原因:有了包,范围变大,一个包中的类要被访问,必须要有足够大的权限。
所以被访问的类要被public修饰。
4、————————————————————————————————
PackageDemo.java:9:show() 在 packa.DemoA 中不是公共的;无法从外部软件包中对其进
行访问
d.show();
^
1 错误
错误原因:类公有后,被访问的成员也要公有才可以被访问。注意,成员公有而类没有公有,同样不可访问。
>>只要是类都能继承,包之间的类继承
eg:packagepacka;
publicclass DomeA extends packb.DemoB
注意:不要忘了,一个java文件里面不能出现一个以上的公有类和接口,
当然,packb.DemoB中得公共方法main函数也能调用,所以,packb.DemoB中的方法可以定义特殊权限“protected”,使得该方法只有DemoB的子类DomeA能调用。
另外,继承中,权限只要大于等于便可以覆盖,比如
DemoB中有方法protect void method(){}
DemoA中定义有方法protect void method(){}覆盖,定义public void method(){}也覆盖。
>>包可以有多层
eg:package pack1.pack2.pack3;//编译后有多层文件夹
那么,我想建立对象
pack1.pack2.pack3.ClassDemoc = new pack1.pack2.pack3.ClassDemo;//太麻烦
所以使用import(导入)
eg:improtpack1.pack2.pack3.ClassDemo;
……
public static void main(String[] args)
{
ClassDemoc = new ClassDemo;
……
}
要导入很多类怎么办?
improt pack1.pack2.pack3.*;//“*”即导入当前包中所有类
注意,如果pack2下有一个类ClassDemo2,然后
improt pack1.pack2.*;
是不能调用ClassDemo的,这个时候必须再写一句
improt pack1.pack2.pack3.*;。
因为pack3为子包。
“*”是通配符,但是实际开发中,最好少用,需要用到那个类,就导入那个类。另外,eclipse可以自动导入。
如果导入的两个包中有重名的类怎么办?
eg:importpacka.*;//其中有ClassDemo
import packa.*;//其中也有ClassDemo
……
//ClassDemoc = new ClassDemo;这样写就不允许了,必须加包名
packa. ClassDemoc = new packa.ClassDemo;
……
>>建议不让包名重复,可以使用url来完成定义,因为url是唯一的。
>>java的压缩包:jar包
方便与项目的携带,方便于使用,只要在classpath是指jar路径即可,数据库驱动,SSH框架等都是以jar包体现的。
用法: jar {ctxui}[vfm0Me] [jar-file] [manifest-file] [entrypoint] [-C dir]files ...
选项包括:
-c 创建新的归档文件
-t 列出归档目录
-x 解压缩已归档的指定(或所有)文件
-u 更新现有的归档文件
-v 在标准输出中生成详细输出
-f 指定归档文件名
-m 包含指定清单文件中的清单信息
-e 为捆绑到可执行 jar 文件的独立应用程序
指定应用程序入口点
-0 仅存储;不使用任何 ZIP 压缩
-M 不创建条目的清单文件
-i 为指定的 jar 文件生成索引信息
-C 更改为指定的目录并包含其中的文件
如果有任何目录文件,则对其进行递归处理。
清单文件名、归档文件名和入口点名的指定顺序
与 "m"、"f" 和 "e" 标志的指定顺序相同。
示例 1:将两个类文件归档到一个名为 classes.jar 的归档文件中
:
jar cvf classes.jar Foo.class Bar.class
示例 2:使用现有的清单文件 "mymanifest" 并
将 foo/ 目录中的所有文件归档到 "classes.jar" 中:
jar cvfm classes.jar mymanifest -C foo/.
eg:把包packa、packb压缩到名叫jardemo(新建)的jar包中
c:\myclass>jar–cf jardemo.jar packa packb
和rar压缩包有什么区别?、
显示jar包中内容的命令“-t”
c:\myclass>jar–tf jardemo.jar
其中头两行
META-INF/
META-INF/MANIFEST.MF
为自动生成的配置文件,可以修改已达到一定功能(比如双击自动执行)。
打包后:set classpath=c:\myclass\jardemo.jar
java 包名.类名
便可以执行了。
>>信息可以存进文件,DOS命令:
比如:c:\dir > c:\show.txt
如果jar包中信息太多,可以这样存。
>>native关键字,本地方法,被它修饰的没有方法体。调用的是系统(win or liunx)功能。
----正则表达式----
>>例子:校验QQ号:不能0开头、需要5-15位、只能为数字
publicstatic void checkQQ(String qq)
{
int len = qq.length();
if(len >= 5 && len <= 15)
{
if(!qq.startsWith("0"))
{
try
{
long l =long.parseLong(qq);
System.out.println("qq:"+l);
}
catch(NumberFormatExceptione)、
{
System.out.println("出现非法字符");
}
}
else
System.out.println("不可以0开头");
}
else
System.out.println("QQ号长度错误");
}//但是这样太麻烦,代码太多
改进方法,使用正则表达式:
publicstatic void checkQQReg(String qq)
{
String qq = "1233568";
String reg ="[1-9][0-9]{4-14}";
boolean b = qq.matches(reg);
System.out.println("b="+b);
}
/*
解释:
1、String reg ="[1-9][0-9]{4-14}";是正则表达式条件,意思是:第一位为1到9的数字,往后还有4到14位数字,它们的范围是0到9的数字。
2、matches(reg);方法:API文档:boolean matches(String regex) //告知此字符串是否匹配给定的正则表达式。
*/
>>正则就是用于操作字符串的规则,其中是以一些符号来表示规则。可以理解为:其实符号就是对应了底层的代码,不用书写代码,而是使用一些符号来表示,简化了书写。
正则可以简化对字符串的复杂操作。
构造 |
匹配 |
|
|
字符 |
|
x |
字符 x |
\\ |
反斜线字符 |
\0n |
带有八进制值 0 的字符 n (0 <= n <= 7) |
\0nn |
带有八进制值 0 的字符 nn (0 <= n <= 7) |
\0mnn |
带有八进制值 0 的字符 mnn(0 <= m <= 3、0 <= n <= 7) |
\xhh |
带有十六进制值 0x 的字符 hh |
\uhhhh |
带有十六进制值 0x 的字符 hhhh |
\t |
制表符 ('\u0009') |
\n |
新行(换行)符 ('\u000A') |
\r |
回车符 ('\u000D') |
\f |
换页符 ('\u000C') |
\a |
报警 (bell) 符 ('\u0007') |
\e |
转义符 ('\u001B') |
\cx |
对应于 x 的控制符 |
|
|
字符类 |
|
[abc] |
a、b 或 c(简单类) |
[^abc] |
任何字符,除了 a、b 或 c(否定) |
[a-zA-Z] |
a 到 z 或 A 到 Z,两头的字母包括在内(范围) |
[a-d[m-p]] |
a 到 d 或 m 到 p:[a-dm-p](并集) |
[a-z&&[def]] |
d、e 或 f(交集) |
[a-z&&[^bc]] |
a 到 z,除了 b 和 c:[ad-z](减去) |
[a-z&&[^m-p]] |
a 到 z,而非 m 到 p:[a-lq-z](减去) |
|
|
预定义字符类 |
|
. |
任何字符(与行结束符可能匹配也可能不匹配) |
\d |
数字:[0-9] |
\D |
非数字: [^0-9] |
\s |
空白字符:[ \t\n\x0B\f\r] |
\S |
非空白字符:[^\s] |
\w |
单词字符:[a-zA-Z_0-9] |
\W |
非单词字符:[^\w] |
|
|
POSIX 字符类(仅 US-ASCII) |
|
\p{Lower} |
小写字母字符:[a-z] |
\p{Upper} |
大写字母字符:[A-Z] |
\p{ASCII} |
所有 ASCII:[\x00-\x7F] |
\p{Alpha} |
字母字符:[\p{Lower}\p{Upper}] |
\p{Digit} |
十进制数字:[0-9] |
\p{Alnum} |
字母数字字符:[\p{Alpha}\p{Digit}] |
\p{Punct} |
标点符号:!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ |
\p{Graph} |
可见字符:[\p{Alnum}\p{Punct}] |
\p{Print} |
可打印字符:[\p{Graph}\x20] |
\p{Blank} |
空格或制表符:[ \t] |
\p{Cntrl} |
控制字符:[\x00-\x1F\x7F] |
\p{XDigit} |
十六进制数字:[0-9a-fA-F] |
\p{Space} |
空白字符:[ \t\n\x0B\f\r] |
|
|
java.lang.Character 类(简单的 java字符类型) |
|
\p{javaLowerCase} |
等效于 java.lang.Character.isLowerCase() |
\p{javaUpperCase} |
等效于 java.lang.Character.isUpperCase() |
\p{javaWhitespace} |
等效于 java.lang.Character.isWhitespace() |
\p{javaMirrored} |
等效于 java.lang.Character.isMirrored() |
|
|
Unicode 块和类别的类 |
|
\p{InGreek} |
Greek 块(简单块)中的字符 |
\p{Lu} |
大写字母(简单类别) |
\p{Sc} |
货币符号 |
\P{InGreek} |
所有字符,Greek 块中的除外(否定) |
[\p{L}&&[^\p{Lu}]] |
所有字母,大写字母除外(减去) |
|
|
边界匹配器 |
|
^ |
行的开头 |
$ |
行的结尾 |
\b |
单词边界 |
\B |
非单词边界 |
\A |
输入的开头 |
\G |
上一个匹配的结尾 |
\Z |
输入的结尾,仅用于最后的结束符(如果有的话) |
\z |
输入的结尾 |
|
|
Greedy 数量词 |
|
X? |
X,一次或一次也没有 比如foo,正则条件fo?,则为false 比如fo,正则条件fo?,则为true |
X* |
X,零次或多次 |
X+ |
X,一次或多次 |
X{n} |
X,恰好 n 次 |
X{n,} |
X,至少 n 次 |
X{n,m} |
X,至少 n 次,但是不超过 m 次 |
|
|
Reluctant 数量词 |
|
X?? |
X,一次或一次也没有 |
X*? |
X,零次或多次 |
X+? |
X,一次或多次 |
X{n}? |
X,恰好 n 次 |
X{n,}? |
X,至少 n 次 |
X{n,m}? |
X,至少 n 次,但是不超过 m 次 |
|
|
Possessive 数量词 |
|
X?+ |
X,一次或一次也没有 |
X*+ |
X,零次或多次 |
X++ |
X,一次或多次 |
X{n}+ |
X,恰好 n 次 |
X{n,}+ |
X,至少 n 次 |
X{n,m}+ |
X,至少 n 次,但是不超过 m 次 |
|
|
Logical 运算符 |
|
XY |
X 后跟 Y |
X|Y |
X 或 Y |
(X) |
X,作为捕获组 |
|
|
Back 引用 |
|
\n |
任何匹配的 nth 捕获组 |
|
|
引用 |
|
\ |
Nothing,但是引用以下字符 |
\Q |
Nothing,但是引用所有字符,直到 \E |
\E |
Nothing,但是结束从 \Q 开始的引用 |
|
|
特殊构造(非捕获) |
|
(?:X) |
X,作为非捕获组 |
(?idmsux-idmsux) |
Nothing,但是将匹配标志idmsux on - off |
(?idmsux-idmsux:X) |
X,作为带有给定标志 idmsux on - off的非捕获组 |
(?=X) |
X,通过零宽度的正 lookahead |
(?!X) |
X,通过零宽度的负 lookahead |
(?<=X) |
X,通过零宽度的正 lookbehind |
(? |
X,通过零宽度的负 lookbehind |
(?>X) |
X,作为独立的非捕获组 |
>>功能:
1、匹配
使用的是String中的matches方法。
eg:………………
publicstatic void method()
{
String str = “qaq”;//需要中间是元音
String reg = “q[aeiou]q”;//判断中间是元音
boolean b = str.matches(reg);
System.out.println(“str:”+b);
}
………………
………………//电话号码匹配
publicstatic void method()
{
String str = “25800001111”;
String reg = “1[25]\\d{9}”;
/*
第一位为1
第二位为3或5
往后九位为数字0-9,可以用\d代表,也可以用[0-9]。
但是注意,“\d”为预定义字符及固定的规则符号,而在字符串中“\”有转义的功能,规则就没有了,需要再加上“\”将“\”转义成普通字符。所以在字符串中定义正则,出现反斜线需要一对出现。
*/
boolean b = str.matches(reg);
System.out.println(“str:”+b);
}
………………
2、切割
使用的是String类中的split方法
eg:………………
public staticvoid splitDemo()
{
/*String str = “aa,bb,cc”;
String[] arr = str.split(“,”);*/
/*String str = “aa.bb.cc”;
String[] arr = str.split(“\\.”);说过的反斜杠特性,以及“.”代表任意字符,需要转义*/
/*String str = “aa bb cc”;任意个空格
String[] arr = str.split(“ +”);*/
/*
String str = “aafhswetbbasgewrgcc”;//需要用叠词切
String[] arr = str.split(“(.)\\1”);
//为了提高规则的复用,用“()”进行封装
//“()”涉及组的概念,一个“()”代表一个组并且按顺序编号,从1开始
//使用时需要对编号进行转义“\\1”代表获取1组规则。
*/
for(String s : arr)// 泛性(j2SE 5.0的新特性)
{
System.out.println(s)
}
}
涉及组时,有组的嵌套,阅读时依据左括号区分,从左到右计算其开括号来编号。例如,在表达式 ( (A ) ( B ( C ) ) ) 中,存在四个这样的组:
1 |
((A)(B(C))) |
2 |
\A |
3 |
(B(C)) |
4 |
(C) |
另外,编号0的组代表整个表达式。
3、替换
使用String类中的replaceAll方法
eg:………………
publicstatic void replaceDemo()
{
/*
String str = “kjaaaasccchfoqqqi”;
String strRe = str.replaceAll(“(.)\\1+”,”#”);//将叠词替换成“#”
System.out.println(str+”:”+strRe);
*/
/*将叠词变成该叠词的第一个字符
String str = “kjaaaasccchfoqqqi”;
String strRe = str.replaceAll(“(.)\\1+”,”$1”);
//“$”可以获取该方法中正则实际参数中的某一组
System.out.println(str+”:”+strRe);
*/
}
………………
4、获取
使用的是正则对象Pattern和Matcher
范例:其实是每个正则方法的底层方法
Pattern p= Pattern.compile("a*b");//ab之间可以有任意字符
Matcher m= p.matcher("aaaaab");//匹配
boolean b= m.matches();
步骤:
1、先将正则表达式编译成正则对象,使用的是Pattern类一个静态的方法:compile(regex);
2、让正则对象和要操作的字符串相关联,通过matcher方法完成,并返回匹配器对象。
3、通过匹配器对象的方法将正则模式作用到字符串上对字符串进行针对性的功能操作。
eg:………………
publicstatic void getDemo()
{
String str = “da jia zhu yi le,mingtian bu fang jia,xie xie”;
//想要获取三个字母组成的单词
//这时我们要用到一些正则对象:关注Pattern类,在java.util.regex.*包中
String reg = “\\b[a-z]{3}\\b”;
//注意加上单词边界“\\b”,否则“ming”中会将“min”取出
Pattern p = Pattern.compile(reg);
Matcher m = p.matcher(str);
/*
System.out.println(m.find);//将规则对字符串进行匹配查找。
System.out.println(m.find);
System.out.println(m.group());//在使用group方法之前,必须先找“find”
//注意:找一次,取的是最后一次找的对象,比如现在输出的是“zhu”而不是“jia”
*/
while(m.find())
{
System.out.println(m.start()+”…”+m.end());//输出字符串角标,注意取头不取尾
System.out.println(m.group());
//其实group()用的是:
//System.out.println(“sub:”+str.substring(m.start(),m.end() ) );
}
}
………………
eg:邮箱地址校验
………………
classRegexDemo2
{
public static void main(String[] args)
{
checkMail();
}
public static void checkMail()
{
Stringmail = “abc123@sina.com”;
Stringreg = “[0-9_a-zA-Z]+@[0-9_a-zA-Z]+(\\.[a-zA-Z]+)+”;
//注意,这里组(\\.[a-zA-Z]+)+
//的作用是,邮箱地址有abc123@sina.com也有abc123@sina.com.cn
//笼统的格式
//reg= “\\w+@\\w+(\\.\\w+)+”;//” \\w”即[0-9_a-zA-Z]
//还有不负责任的判断:mail.index(“@”)! = -1; 不要这样判断
booleanb = mail.matches(reg);
System.out.println(mail+”:”+b);
}
}
………………
eg:还原口吃的字符串
“我我…我…………我.要. 要要…………要要要要..学学…学..编..编…编..编程”
还原成“我要学编程”
……………………
public static void showStr()
{
Stringstr = “我我…我…………我.要. 要要…………要要要要..学学…学..编..编…编..编程”;
/*
1、先将字符串中的“.”去掉
2、将没有“.”的字符串进行叠词处理
*/
str= str.replaceAll(“\\.”,””);
System.out.println(“str= ”+str);
str= sr.replaceAll(“(.)\\1+”,”$1”);
System.out.println(“str = ”+str);
}
………………
eg:ip地址按照从小到大顺序排序
192.168.3.23202.10.34.2 3.3.3.3 127.0.0.1 80.12.23.34
思路:使用字符串排序的方式按照自然顺序进行比较即可。
但是因为每段地址的位数不相同,会导致排序的错乱。比如3.3.3.3与127.0.0.1如果按照字符串的顺序比较,127会排序到3的前面。因为1比3小。
但是3.3.3.3作为A类地址,应该排序到前面。
问题出现,每一段排序比较时,对应的位数不同。3于最后一位,127的1为该段第一位。
这样比较不合适。
所以,最好将每一个ip中的地址段,都变成3位,不满足的用0补。
即003.003.003.003与127.000.000.001,这时再比较,003就会排序在127的前面。
步骤:
1、给每段地址补0的动作,无论每段地址有几位,至少有1位,所以先按照最低位数的补0原则进行补0,也就是每段都补两个0。
2、发现有的地址段超出了3位,这时对每一段进行只保留3位的操作。
………………
importjava.util.*
………………
publicstatic void ipSort()
{
String ip = “192.168.3.23 202.10.34.23.3.3.3 127.0.0.1 80.12.23.34”;
//补零动作
ip = ip.replaceAll(“(\\d+)”,”00&1”);
Sysem.out.println(“ip = ”+ip);
//还原3位动作
ip = ip.replaceAll(“0*(\\d{3})”,”$1”);
Sysem.out.println(“ip = ”+ip);
//按空格切
String ips = ip.split(“ +”);
TreeSet
for(String I : ips)
{
ts.add(i);
}
for(String I : ts)
{
//输出且除去多余的0
System.out.println(i.repalceAll(“0*(\\d+)”,”$1”));
}
}
………………
eg:邮件地址爬虫
一种应用程序,获取指定规则的数据
需求,想要获取到指定文件所有mail地址。
思路:
1、读取这个文件
2、读取文件中的每一行
3、让每一行和规则相关联,获取符合规则的字符串
…………
importjava.io.*;
importjava.util.regex.*;
importjava.net.*;
…………
classGetMailList
{
public static void main(String[] aargs)throws Exception
{
String reg = “\\w+@[a-zA-Z]+(\\.[a-zA-Z]+)+”;
getMails(reg);
}
//本地文件方法
public static void getMails(Stringregex) throws Exception
{
//源
BufferedReader bufr =
newBufferedReader(new FileReader(“mail.txt”));
String line = null;
Pattern p =Pattern.compile(regex);
while((line =bufr.readLine())!=null)
{
//System.out.println(line);
Matcher m =p.matcher(line);
while(m.find())
{
System.out.println(m.group());
}
}
}
//网络方法
public static void getMails(Stringregex) throws Exception
{
//源
URL url = new URL(“http://www.baidu.com”);
URLConnection conn =url.openConnection();
BufferedReader bufIn = new BufferedReader(newInputStreamReader(
conn.getInputStream() ) );
String line = null;
Pattern p =Pattern.compile(regex);
while((line = bufIn.readLine())!=null)
{
//System.out.println(line);
Matcher m =p.matcher(line);
while(m.find())
{
System.out.println(m.group());
}
}
}
}
…………