2019/1/16 Java语言程序设计-类与对象 教师:段鹏飞
为什么要用正则表达式 我们在电脑中搜索一个文件,一般搜索文件名:java.ppt 如果要查找所有的ppt呢? *.ppt
关于正则表达式 条条大道通罗马 正则测试网址
正则表达式基础知识 我们先从简单的开始。假设你要搜索一个包含字符“cat”的字符串,搜索用的正则表达式就是“cat”。如果搜索对大小写不敏感,单词“catalog”、“Catherine”、“sophisticated”都可以匹配。也就是说:
1.1 句点符号 假设你在玩英文拼字游戏,想要找出三个字母的单词,而且这些单词必须以“t”字母开头,以“n”字母结束。 可以使用一个通配符——句点符号“.”。这样,完整的表达式就是“t.n”,它匹配“tan”、“ten”、“tin”和“ton”,还匹配“t#n”、“tpn”甚至“t n”。
1.2 方括号符号 “.” 搜索的内容太多了,可以在方括号 “[]” 里面指定看来有意义的字符。只有方括号里面指定的字符才参与匹配。也就是说,正则表达式“t[aeio]n”只匹配“tan”、“Ten”、“tin”和“ton”。但“toon”不匹配,因为在方括号之内你只能匹配单个字符:
1.3 “或”符号 如果想要匹配“toon”,那么,你可以使用“|”操作符。 “|”操作符的基本意义就是“或”运算。要匹配“toon” ,使用“t(a|e|i|o|oo)n”正则表达式。这里不能使用方扩号,因为方括号只允许匹配单个字符;这里必须使用圆括号“()”。
1.4 表示匹配次数的符号 如何用“[]”来表示“toon” t[o]+n
1.4 表示匹配次数的符号 假设我们要在文本文件中搜索美国的社会安全号码。这个号码的格式是999-99-9999,如何表示? (“-”)有着特殊的意义,它表示一个范围,比如从0到9
1.5 “否”符号 “^”符号称为“否”符号。如果用在方括号内, “^”表示不想要匹配的字符。例如,图四的正则表达式匹配所有单词,但以“X”字母开头的单词除外。
1.6 其它符号 [A-Za-z0-9] [^A-Za-z0-9]
示例 非负整数:[1-9]\d*|0 正整数:[1-9]\d* 英文字符串:[A-Za-z]+ Email地址: \w{1,}@\w{1,}\.\w{1,}
程序 String regex="\\w{1,}@\\w{1,}\\.\\w{1,}" ; String str1="zhangsan@sina.com"; String str2="li@si@dl.cn"; if(str1.matches(regex)) { System.out.println(str1+"是一个Email地址"); }else { System.out.println(str1+"不是一个Email地址"); } if(str2.matches(regex)) System.out.println(str2+"是一个Email地址"); System.out.println(str2+"不是一个Email地址");
关于程序中中文的问题
2019/1/16 知识点 1、关于static的使用方法 2、类的初始化 2、Java类继承的特点 3、封装、继承和多态的使用方法 4、继承的访问权限(private) 5、接口的定义及使用
示例 Scanner in = new Scanner(System.in); 制造对象与使用对象 示例 Scanner in = new Scanner(System.in); double a = Double.parseDouble(in.next()); double a = in.nextDouble(); System.out.println()?
static (静态变量/静态方法) static 类的变量/方法,独立于类的对象,可以直接根据类名调用 class S { static int A = 12, B = 34; static void print() { … } } class Test { public static void main(String args[]) { System.out.println(“A=“ + S.A + “ B=“ + S.B); S.print(); static方法中仅仅可以调用其他static方法
main方法就是static 静态成员变量可以进行数据的共享 静态方法 类的静态成员 装载至内存的时间:JVM在加载.class文件时 通过类名+点运算符调用 只能调用静态方法和静态属性
提供了常用的数学函数 示例 Math.abs(123.45); Math.ceil(123.45);//向上取整数 Math.floor(123.45);//向下取整数 Math.max(-1.5, 1.5); Math.random(); //随机行为
对象变量的赋值 基本数据类型的赋值 对象变量之间的赋值 两个变量指向同一个对象 赋值运算符左侧的变量原先指向的空间可能被回收
代码一 代码二 小测试:下面两段代码的输出? int a; int b; a = 32; b = a; a = a + 1; System.out.println(b); Person a; Person b; a = new Person("Tom"); b = a; a.changeName("Eric"); System.out.println(b.getName());
方法调用(method-calling) 调用对象的方法 方法调用(method-calling) 在Java中,对象通过调用其他对象的方法来进行互相之间的“通信”。 返回值(return value) 返回值是方法调用的结果 方法可以通过返回值来返回对象的信息。 当一个方法不需要返回值的时候,使用void表示不需要返回值。Eg:main方法 方法的参数 参数的数量、类型、顺序的正确 基本数据类型参数是“值传递” 对象类型参数是“址传递”,被调用方法会改变原对象
定义时初始化 private int value=10; private String name = "James Goslin"; 对象的初始化 定义时初始化 private int value=10; private String name = "James Goslin"; private String[] array = new String[10];
所有的数值类型 字符类型 逻辑类型 对象类型 整型,0 浮点型,0.0 Unicode编码为0的不可见字符 false null 初始化时属性的缺省值 所有的数值类型 整型,0 浮点型,0.0 字符类型 Unicode编码为0的不可见字符 逻辑类型 false 对象类型 null
一个直接的做法是在定义数据成员的同时也为其赋值。 class Measurement { boolean b=true; 定义初始化 一个直接的做法是在定义数据成员的同时也为其赋值。 class Measurement { boolean b=true; char c='x'; int i=47; }; 也可以用相同的方法初始化对象。 Depth o = new Depth();
可以调用一个方法进行初始化 class CInit { int i = f(); // ... } 当然这个方法也可以使用参数 int i = f(); int k = g(i); // ... }; 但是那些参数不能是尚未初始化的其它数据成员。 class CInitWrong { int j = g(i); int i = f(); // ...
构造方法,一种特殊的方法 缺省构造方法 自定义构造方法 对象的初始化(续) 方法名称就是类的名称 没有返回类型 自动被调用 不能通过点运算符调用 缺省构造方法 无参数的构造方法 Java编译器自动配置,满足编译需要 自定义构造方法 有参数的构造方法 传递适当参数值进行调用
方法重载 多个方法的名称相同,但是参数表不同 方法的签名 参数的个数 参数的顺序 参数的类型 不包括返回类型
构造方法的重载 普通方法的重载 this关键字 特殊的对象变量 方法重载(续) this.name="Lim"; 常用于IDE自动生成的构造方法和set方法
访问控制 封装的定义 隐藏数据 开放操作 Java修饰符 public protected 无修饰符 private
类成员(属性和方法)的可见性 属性是private 访问操作是public 普通方法不限制 访问控制(续1) getXXX() setXXX() 普通方法不限制
访问控制(续2) 类的可见性
目录 1、封装 2、继承 3、多态 4、接口
计算器 命名不规范 不能用“==” 用if效率低
计算器
曹操的故事……
曹操的故事……
这些字并非用完这次就无用,完全可以在后来的印刷中重复使用,此为可复用; 活字印刷优点 要改,只需要改要改之字,此为可维护; 这些字并非用完这次就无用,完全可以在后来的印刷中重复使用,此为可复用; 此诗若要加字,只需另刻字加入即可,此为可扩展; 排版可能是竖排或横排,只需将活字移动就可以做到,此为灵活性好。
复制VS重用
业务封装
紧耦合 VS 松耦合
类的调用
Java语言中有三个典型的面向对象的特性:封装性、继承性和多态性 。 面向对象特性 Java语言中有三个典型的面向对象的特性:封装性、继承性和多态性 。
下面代码有什么问题? 如何解决上面设计的缺陷? 为什么要使用封装 使用封装 Student stu = new Student(); stu.java = 200; 不合理的赋值 使用封装
面向对象三大特征之一——封装 1、什么是封装? 封装的概念 封装的好处 封装:将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问 隐藏类的实现细节 只能通过规定方法访问数据 方便加入控制语句 方便修改实现
封装性 1、为什么要使用封装? 对象本身的数据得到保护/隐藏 其他对象仅仅需要知道对该对象的访问方法(接口/interface)即可 好处 模块化--每个对象的源文件可以是相互独立的,可以被不同的程序调用,每个对象是一块积木,可以搭建不同的形状 信息隐藏--通常定义一个公共接口/方法实现对对象的访问,可以调整对象的私有信息和方法,而不会对其他调用它的对象产生影响 可重用性 黑盒子 电脑的DIY 喷墨打印机,硒鼓坏/彩色硒鼓
在getter/setter方法中加入属性控制语句 1、如何使用封装 封装的步骤 修改属性的可见性 设为private 创建getter/setter方法 用于属性的读写 对属性值的合法性进行判断 在getter/setter方法中加入属性控制语句
1、如何使用封装 1 2 2 3 class Student { private float java = 0; private float database=0; private float html=0; public float getJava() { return java; } public void setJava (int java) { if (java > 100 || java < 0) { this.java = 60; System.out.println(“Java成绩在0和100之间,默认值是60"); } else this.java = java; // 其它getter/setter方法 1 2 2 3 this代表当前对象
继承性 2、继承 为什么会有继承? 父类和子类,子类继承(拥有)父类所有的数据和方法,同时子类可以有新的数据和方法,“青出于蓝,而胜于蓝” 建立一个类后,发现另一个新的类有相同的特性,两个选择:重新定义一个新的类;在已有类的基础上,修改(加加/减减) 父类和子类,子类继承(拥有)父类所有的数据和方法,同时子类可以有新的数据和方法,“青出于蓝,而胜于蓝” 树型结构(层次化结构) 根(基类)
2、继承 问题:一个类能否继承两个或多个父类? 运输工具 航空运输工具 陆地运输工具 水上运输工具 人力驱动 引擎驱动 二轮 四轮 客运 货运 问题:一个类能否继承两个或多个父类?
父类与子类的关系 (extends) 基本内容 子类可调用父类的方法和变量,子类可增加父类中没有的方法和变量 2、类的继承 父类与子类的关系 (extends) 基本内容 子类可调用父类的方法和变量,子类可增加父类中没有的方法和变量 子类可重新定义父类的静态/实例变量 子类可重新定义父类的静态/实例方法 继承中的构造方法 类成员访问修饰符与继承的关系
子类可调用父类的方法和变量 子类可增加父类中没有的方法和变量 类的继承 Bus b = new Bus(); class Vehicle { String brand; void setB(String s) { brand = s; } void showB() { System.out.println(brand); } } Bus b = new Bus(); b.setB(“audi”); //** b.setL(710); b.showB(); //** b.showL(); 子类继承父类的方法和变量,则这些方法和变量就属于子类, 则子类对象对这些方法和变量的调用是显而易见的 class Bus extends Vehicle { int line; void setL(int l) { line = l; } void showL() { System.out.println(line); } }
子类可重新定义父类中已有的变量 B b = new B(); 256 x 5.0 321 类的继承 b.show(); class A { int i=256, j =64; static int k = 32; final float e = 2.718f; } B b = new B(); b.show(); b.showA(); 256 x 5.0 321 64 32 2.718 类的继承 子类可重新定义父类中已有的变量 父类中同名的变量无效(隐藏) 通过“super.变量名” 和父类名.变量名(static变量)引用 super ? 当前对象/当前对象的父对象/其他 class B extends A { public char j=‘x’; final double k =5; static int e =321; void show() { System.out.println(i + “ “ + j + “ “ + k + “ “ + e); } void showA() { System.out.println(super.j + “ “ + A.k + “ “ + super.e); } } this.变量名 this.方法名 this() super.变量名 super.方法名 super()
2、继承中的super对象 父类 调用父类的 变量和方法 this super 子类 实例化一个子类对象 调用子类的 变量和方法
2、继承与组合 class Engine { public void start() {} public void rev(){} public void stop() {} } public class Car { public Engine engine = new Engine(); public Wheel[] wheel = new Wheel[4]; public Door left = new Door(); public Door right = new Door(); public Car() { for (int i =0; i < 4; i++) wheel[i] = new Wheel(); } public static void main(String args[]) { Car car = new Car(); car.left.window.rollup(); car.wheel[0].inflate(72); 2、继承与组合 class Wheel { public void inflate(int i) {} } 组合: 有一个 (has-a) 继承: 是一个 (is-a) class Door { public Window window = new Window(); public void open(){} public void close(){} } class Window { public void rollup() {} public void rolldown() {} }
2、继承中的构造方法 子类的构造方法 必须调用 父类的构造方法 class Art { Art() { System.out.println("Art Constructor"); } 2、继承中的构造方法 class Drawing extends Art { /*Drawing() { System.out.println("Drawing Constructor"); }*/ } class Drawing extends Art { Drawing() { System.out.println("Drawing Constructor"); } Art Constructor Drawing Constructor Cartoon Constructor Art Constructor Cartoon Constructor public class Cartoon extends Drawing { Cartoon() { super(); System.out.println("Cartoon Constructor"); } public static void main(String args[]) { Cartoon c = new Cartoon(); public class Cartoon extends Drawing { Cartoon() { System.out.println("Cartoon Constructor"); } public static void main(String args[]) { Cartoon c = new Cartoon(); 子类的构造方法 必须调用 父类的构造方法
再谈继承中的构造方法 类的继承 子类的构造方法 必须要对父类的 构造方法进行 调用, 不管以任何形式, 否则编译出错 class Game { Game(int i) { System.out.println(“Game Constructor"); } 类的继承 再谈继承中的构造方法 class BoardGame extends Game { BoardGame(int i) { super(i); System.out.println(“BoardGame Constructor"); } 子类的构造方法 必须要对父类的 构造方法进行 调用, 不管以任何形式, 否则编译出错 public class Chess extends BoardGame { Chess() { super(3); System.out.println("Cartoon Constructor"); } public static void main(String args[]) { Chess c = new Chess();
再谈子类对父类变量的继承 类的继承 目录结构 /points/Point.class /points/Point3d.class package points; public class Point { int x, y; public void move(int dx, int dy) { x += dx; y += dy; } } 类的继承 再谈子类对父类变量的继承 package points; public class Point3d extends Point { int z; public void move(int dx, int dy, int dz) { x += dx; y += dy; z += dz; } 目录结构 /points/Point.class /points/Point3d.class /Point4d.class 继承与类成员的访问修饰符有关! import points.Point3d; class Point4d extends Point3d { int w; public void move(int dx, int dy, int dz, int dw) { x += dx; y += dy; z += dz; w += dw; } import points.Point3d; class Point4d extends Point3d { int w; public void move(int dx, int dy, int dz, int dw) { super.move(dx, dy, dz); w += dw; } 编译时报错: x, y, z仅在本包 中才能访问
类成员访问修饰符与继承的关系 2、类的继承 私有的(private)类成员不能被子类继承 公共的(public)和保护性的(protected)类成员能被子类继承,且子类和父类可以属于不同的包 无修饰的父类成员,仅在本包中才能被子类继承 构造函数不是类成员,所以不被继承
名称 访问权修饰符 类本身 子类 包 所有类 公共 public 默认 --- 保护 protected * 私有 private 2、访问权限 名称 访问权修饰符 类本身 子类 包 所有类 公共 public 默认 --- 保护 protected * 私有 private * 指子类与父类不在同一个包中的情况
表现在继承中方法的重写 表现在用一个类中方法的重载 3、多态性 子类从父类继承(extends扩展)而来 多个子类同属一个父类,所有子类有相同的父类 继承父类的方法 在不同的子类中有不同的表现形式 表现在用一个类中方法的重载
3、多态性在继承中的表现
3 多态 3.1向上转型(upcasting) 3.2动态绑定 3.3构造器中多态方法的行为 3.4向下转型
3.1 向上转型(upcasting) public class Shape{ void draw(){} static void start(Shape s){ s.draw(); } public static void main(String [] agrs){ start(new Circle()); start(new Square()); } class Circle extends Shape{ void draw(){System.out.println(“draw Circle”);} class Square extends Shape{ void draw(){System.out.println(“draw Square”);}
3.1 向上转型(upcasting) 在start()方法中,通过传入的参数类型不同,表现出来的行为也会不同。但是传入后的参数都统一转型为Shape这个基类型,这里就表现为向上转型。 由导出类到基类,从继承图上面我们可以看出是向上移动的,因此我们一般称之为“向上转型”。 向上转型是从一个较具体的类型转换为一个较抽象的类型的过程,所以说是安全的。在导出类中至少包含了基类的方法。在向上转型的过程中,由于在导出类中可能含有基类中没有的方法。类接口会丢失一些方法
将一个方法调用同一个方法主体关联起来被称之为绑定,若在程序执行前绑定就被称为前期绑定。 3.2 动态绑定 将一个方法调用同一个方法主体关联起来被称之为绑定,若在程序执行前绑定就被称为前期绑定。 后期绑定也被称为动态绑定,编译器始终都不会知道对象的类型,只有当方法在运行期间被调用时方法的调用机制就能找到正确的方法体。
3.3 构造器中多态方法的行为 public class Shape3{ Shape3(){ System.out.println(“this is a shape”); draw(); } void draw(){} public static void main(String [] agrs){ Shape3 circle = new Circle(); } } class Circle extends Shape3{ int i = 100; Circle(){ draw(); void draw(){System.out.println(“draw Circle” + i);} 最后的输出结果是: this is a shape draw Circle0 draw Circle100
3.3 构造器中多态方法的行为 I、在其他任何事物发生之前,将分配给对象的存储空间初始化为二进制的零。 II、如前所述的那样调用基类构造器。因此我们会发现,虽然在基类的构造器中调用了其子类的draw方法,而里面的i值还并没有被初始化,但由于步骤1的原因,i的值被置为0。 III、按照声明顺序调用成员的初始化方法。 IV、调用子类的构造器主体。
由于向上转型会丢失一些具体的类型的信息,因此我们考虑用向下转型的方式,也就是和向下转型相反的方向转型。 3.4 向下转型 由于向上转型会丢失一些具体的类型的信息,因此我们考虑用向下转型的方式,也就是和向下转型相反的方向转型。
3.4 向下转型 class A { public void f() {}; public void g() {}; } class B extends A{ public void h() {}; class C extends A{ public void u() {}; class D extends A{ public class testRtti { public static void main(String[] args) { A a1 = new A(); A a2 = new B(); A a3 = new C(); a1.f(); a2.g(); a3.g(); //a2.h(); (B)a2.h();//向下转型 (C)a2.h();//异常 }
类D和基类A看作是一种纯粹的“is-a”的关系 。 3.4 向下转型 类B、类C和类D有共同的父类 。 类D和基类A看作是一种纯粹的“is-a”的关系 。 类B和类C中我们对基类进行了扩展,类B、C和A是is-like-a的关系。将他们向上转型后,他们特有的方法和属性就会丢失,如果需要找回这些属性和方法我们就需要进行强制的类型转换。 使用(B)a2.h()这样的方式来强制转换成B这个类型 ,会抛出ClassCastException 。
接口中的方法都是未实现的(类似于抽象方法),目的是在实现接口的类之间建立一种协议 接口中的变量都是常量 定义 4、接口 接口是对abstract类的进一步扩展 接口中的方法都是未实现的(类似于抽象方法),目的是在实现接口的类之间建立一种协议 接口中的变量都是常量 定义 一个类符合某个或一组接口,利用implements class 类名 implements 接口1, 接口2 …… { … … … } [public] interface 接口名 { 成员变量; 方法声明; }
接口变量默认都是“public static final” 接口 (interface) 接口名修饰 public: 无任何访问限制 无修饰: 仅限于本包中 接口变量默认都是“public static final” public interface Months { int JANUARY=1, FEBRUARY=2, MARCH=3, APRIL=4, MAY=5, JUNE=6, JULY=7, AUGUST=8, SEPTEMBER=9,OCTOBER=10, NOVEMBER=11,DECEMBER=12; }
但在实现接口方法的类中,修饰符为public 4、接口方法 interface Figure { double half=0.5,pi=3.14159; void parameter(); void area(); } class Circle implements Figure { double x, y, r; Circle(double u, double v, double m) { x=u; y=v; r=m; } public void parameter() { System.out.println(x+“ “+y+“ “+r); } public void area() { System.out.println(pi*r*r); } } 无修饰 但在实现接口方法的类中,修饰符为public class Triangle implements Figure { double b, h; Triangle (double u, double v) { b = u; h = v; } public void parameter() { System.out.println(b + “ “ + h); public void area() { System.out.println(half*h*b); } Triangle t = new Triangle(2, 3); Circle c = new Circle(4, 5, 6); Figure[] f = {t, c}; for (int i =0; i < f.length; i++) { f[i].parameter(); f[i].area(); }
2019/1/16 谢谢