概述
(材料源于网络)
Java SE 3rd day:Object-oriented 02
1、本次课程知识点
1、引用数据的操作深入;
2、this关键字的使用;
3、对象数组的概念及操作;
4、引用的实际问题分析;
2、具体内容
2.1 引用数据类型的回顾(重点)
下面编写三道题目,通过题目来简单的对引用传递的操作作一个回顾。
范例:第一道引用范例
class MyReasult { private int num = 10;
public void setNum(int n) { num = n; }
public int getNum() { return num; } }
public class StringDemo { public static void main(String args[]) { MyReasult mr = new MyReasult(); mr.setNum(100); fun(mr); System.out.println(mr.getNum()); }
public static void fun(MyReasult temp) { temp.setNum(30); } } |
30 |
下面通过内存关系图进行分析,在分析之前再一次回顾一下概念:
● 堆内存:保存的是对象的属性信息;
● 栈内存:保存的是一块堆内存的操作地址;
本程序是一个标准的引用传递操作,即:一块堆内存空间被两块栈内存所指向。
范例:第二道引用范例
public static void main(String args[]) { String mr ="Hello"; fun(mr); System.out.println(mr); }
public static void fun(String temp) { temp="MLDN"; } |
Hello |
本题目的解决关键有一点:字符串的内容不可改变,改变的是内存地址的指向,所以对于String而言最方便的理解是按照一个普通的数字传递那样理解。
package course_2;
class MyReasult { private String msg = "Hello";
public void setMsg(String m) { msg = m; }
public String getMsg() { return msg; } }
public class StringDemo { public static void main(String args[]) { MyReasult mr = new MyReasult(); mr.setMsg("World"); fun(mr); System.out.println(mr.getMsg()); }
public static void fun(MyReasult temp) { temp.setMsg("MLDN"); } } |
MLDN |
本程序的问题解决思路与第一道题完全一样,但是这个题目的内存关系图有两种画法:
第一种:简单理解,与第一道思路一样。
第二种:完整画法
String本身就是一个对象,所以理论上应该也有自己的内存分配,于是现在的内存分配如下:
而且String是引用类型,但是对于String的理解可以简单的按照基本数据类型那样,所以以上的完整的内存图表示,只是作为参考,严格来讲,现在的程序就相当于是引用的引用。
2.2 this关键字(重点)
在整个java之中,this关键字是一个最难理解的关键字,this有三种用处:表示属性、表示方法、表示当前对象。
2.2.1 表示属性
在之前的代码中可以发现,可以通过构造方法或者是setter方法为类中的属性赋值,但是,如果说现在代码写成如下的形式:
class Person { private String name; private int age;
public Person(String a, int n) { name = a; age = n; }
public String getInfo() { return "Name: " + name + ",age: " + age; } }
public class StringDemo { public static void main(String args[]) { Person per = new Person("Jones", 30); System.out.println(per.getInfo()); } } |
Name: Jones,age: 30 |
此时的构造方法,是希望传入两个属性的内容,但是这个构造方法的参数名称并不明确,因为字母“a”和“n”都没有任何的意义,所以现在希望修改构造方法的参数,与类中的属性同名。
public Person(String name, int age) { name = name; age = age; } |
Name: null,age: 0 |
这个时候构造方法上的确是可以清楚的知道要传递的是name和age的信息,但是最后的结果并没有真正的将传入的name和age两个属性赋予类中的name和age属性,在程序的开发之中,是以“{}”为界,存在一种称为就近原则,因为这个原则,所以之前构造方法中出现的name和age两个参数都是构造方法的参数,与类中的属性没有关系,所以,如果现在想要明确的表示操作的是类中属性的话,则可以使用“this”属性的操作形式。
class Person { private String name; private int age;
public Person(String name, int age) { this.name = name; this.age = age; }
public String getInfo() { return "Name: " + this.name + ",age: " + this.age; } //此处的name和age可加可不加this }
public class StringDemo { public static void main(String args[]) { Person per = new Person("Jone", 30); System.out.println(per.getInfo()); } } |
Name: Jone,age: 30 |
建议:在以后的开发之中,方法里面肯定会有参数,也会使用到类中的属性,为了更好的区分,以后只要是类中的属性都必须子在前面加上“this”。
2.2.2 调用方法
如果现在想明确的表示出调用的是本类中方法的话,则使用“this.方法()”的形式,但是对于方法的调用在java中分为两种:一种是普通方法,另外一种就是构造方法。
如果现在希望在一个类中完成构造方法的互调用,则可以使用“this.()”的操作形式,里面可以根据需要传递进若干个参数。
范例:现在类中有三个构造方法,但是这三个构造方法不管调用哪一个,都要执行一段固定的输出“一个新的实例化对象产生”,那么如果说现在按照之前的做法,则代码实现如下:
class Person { private String name; private int age;
public Person() { System.out.println("A new object of Person produce."); }
public Person(String name) { System.out.println("A new object of Person produce."); this.name = name; }
public Person(String name, int age) { System.out.println("A new object of Person produce."); this.name = name; this.age = age; }
public String getInfo() { return "Name: " + this.name + ",age: " + this.age; } }
public class StringDemo { public static void main(String args[]) { Person per = new Person("Jone", 30); } } |
A new object of Person produce. |
但是,以上的实现手段存在了重复代码。所以使用传统的方法不好使,那么使用this完成。
class Person { private String name; private int age;
public Person() { System.out.println("A new object of Person produce."); }
public Person(String name) { this(); //调用本类的无参构造 this.name = name; }
public Person(String name, int age) { this(name); //调用有一个参数的构造 this.age = age; }
public String getInfo() { return "Name: " + this.name + ",age: " + this.age; } }
public class StringDemo { public static void main(String args[]) { Person per = new Person("Henry",58); } } |
A new object of Person produce. |
以上的程序是完成了this调用构造的操作形式,但是也同时存在以下的几个注意点:
● 使用this调用构造方法的操作,只能在类中的构造方法的首行;
● 【关键】一个类中虽然可以使用this进行构造方法的互调用,但是一定要保留一个构造方法,是不使用this调用的,以作为程序的出口;
范例:错误的操作
public Person() { this("",0); //调用两个参数的构造 System.out.println("A new object of Person produce."); } public Person(String name) { this(); //调用无参的构造 this.name = name; } public Person(String name, int age) { this(name); //调用一个参数的构造 this.age = age; } |
很明显,可以发现本程序的问题,所以编译器的话也可以自动为用户解决,直接报错。
错误:“recursive construction invocation”,递归构造调用;
2.2.3 表示当前对象
所谓的当前对象指的是当前正在调用类中方法的对象,为了解释此概念,下面先观察这样的一个程序:
package course_2;
class Person { }
public class StringDemo { public static void main(String args[]) { Person per1 = new Person(); Person per2 = new Person(); Person per3 = new Person(); System.out.println(per1); // 直接打印对象 System.out.println(per2); System.out.println(per3); } } |
course_2.Person@51cfc277 course_2.Person@1ee83c97 course_2.Person@20e1ed5b |
现在的程序是直接输出了对象的信息“”,默认情况下是一串地址信息,所以默认的对象打印就是地址信息,不同的实例化对象地址信息也肯定不一样。
package course_2;
class Person { public void print() { System.out.println("Person this= " + this); } }
public class StringDemo { public static void main(String args[]) { Person per1 = new Person(); Person per2 = new Person(); System.out.println("MAIN= " + per1); // 直接打印对象 per1.print(); System.out.println("MAIN= " + per2); per2.print(); } } |
MAIN= course_2.Person@50a6023a Person this= course_2.Person@50a6023a MAIN= course_2.Person@42dc5733 Person this= course_2.Person@42dc5733 |
那么之前的“this.属性”严格来讲,含义应该表示成“当前对象的属性”,分析下面一道比较复杂的题目:
package course_2;
class A { private B var;
public A() { // 2、执行此构造方法 this.var = new B(this); // 3、实例化B类对象,this=a; this.var.get(); // 6、通过B类对象var调用类的get()方法 }
public void print() { // 8、执行输出 System.out.println("Hello World. "); } }
class B { private A temp;
public B(A temp) { // 4、执行此构造,这个时候的temp就是a this.temp = temp; // 5、将外部的a的实例给了B的temp属性 }
public void get() { this.temp.print(); // 7、此方法通过A的对象temp调用A的print()方法 } }
public class StringDemo { public static void main(String args[]) { A a = new A(); // 1、调用构造方法 } } |
Hello World. |
本题目的:this在任何情况下都表示当前对象。
2.2.4 思考题
编写一个公司员工类:Employee,类的组成如下:
● 数据成员:员工号、姓名、薪水、部门
● 操作方法:
|- 利用构造方法完成设置信息:
A、单参,只传递员工号,则员工姓名:无名氏,薪水:0,部门:未定
B、双参,传递员工号,姓名,则员工薪水为 1000,部门:后勤
C、四参,传递员工号,姓名,部门,薪水
D、无参,则均为空值
|- 显示信息
|- 提示:暂时不用编写setter、getter
DIY |
package course_2;
class Employee { private int empno; private String ename; private int sal; private String dept;
public Employee() { this.empno = 0; this.ename = null; this.sal = 0; this.dept = null; }
public Employee(int empno) { this.empno = empno; this.ename = null; this.sal = 0; this.dept = "未定"; }
public Employee(int empno, String ename) { this.empno = empno; this.ename = ename; this.sal = 1000; this.dept = "后勤"; }
public Employee(int empno, String ename, int sal, String dept) { this.empno = empno; this.ename = ename; this.sal = sal; this.dept = dept; }
public void printInfo() { System.out.println(empno + " " + ename + " " + sal + " " + dept); } }
public class StringDemo { public static void main(String args[]) { Employee emp = new Employee(10, "Henry", 2400, "Seller"); emp.printInfo(); } } |
10 Henry 2400 Seller |
Answer |
package course_2;
class Employee { private int empno; private String ename; private double sal; private String dept;
public Employee() { }
public Employee(int empno) { this(empno, "无名氏", 0.0, "未定"); }
public Employee(int empno, String ename) { this(empno, ename, 1000.0, "后勤"); }
public Employee(int empno, String ename, double sal, String dept) { this.empno = empno; this.ename = ename; this.sal = sal; this.dept = dept; }
public String getInfo() { return "雇员信息:" + "n" + "t|- 雇员 编号:" + this.empno + "n" + "t|- 雇员 姓名:" + this.ename + "n" + "t|- 雇员 工资:" + this.sal+ "n" + "t|- 雇员 部门:" + this.dept; } }
public class StringDemo { public static void main(String args[]) { System.out.println(new Employee(7369, "Smith", 800.0, "财务部").getInfo()); } } |
雇员信息: |- 雇员 编号:7369 |- 雇员 姓名:Smith |- 雇员 工资:800.0 |- 雇员 部门:财务部 |
本题目的目的是为了巩固构造方法间的互调用操作。
2.3 对象数组(重点)
数组是一组相关变量的集合,而对象数组,就是一组相关对象的集合,对象数组的定义方式与数组的格式一样,也分为两种:
格式一:动态初始化
● 声明并开辟数组空间:
类名称 对象数组名称[ ] = new 类名称[长度]; |
类名称 [ ] 对象数组名称 = new 类名称[长度]; |
● 分步完成:
声明对象数组: | 类名称 [ ] 对象数组名称 = null; |
为数组开辟空间: | 对象数组名称 = new 类名称 [长度]; |
如果使用的是动态初始化对象数组的形式,则开辟空间之后,数组中的每一个元素的内容都是null。
格式二:静态初始化
类名称 [ ] 对象数组名称 = { 实例化对象1,实例化对象2…} ; |
类名称 [ ] 对象数组名称 = new 类名称 { 实例化对象1,实例化对象2…} ; |
静态初始化之后,里面的内容就不会是null。
范例:动态初始化
package course_2;
class Person { private String name; private int age;
public Person(String name, int age) { this.name = name; this.age = age; }
public String getInfo() { return "Name:" + this.name + ",Age:" + this.age; } }
public class StringDemo { public static void main(String args[]) { Person per[] = new Person[3]; // 开辟3个空间 System.out.println(per); for (int i = 0; i < per.length; i++) { System.out.println(per[i]); } per[0] = new Person("Mary", 25); per[1] = new Person("Henry", 28); per[2] = new Person("Jones", 27); for (int i = 0; i < per.length; i++) { System.out.println(per[i].getInfo()); } } } |
[LfirstCourse.Person;@3148aa23 null null null Name:Mary,Age:25 Name:Henry,Age:28 Name:Jones,Age:27 |
使用动态初始化之后,数组中的每一个元素都必须分别进行对象的实例化操作。
注意:比较上面两个输出,如果只执行分步定义的第一步后,在输出语句后面加“.getInfo()”,则编译不了而出错;如果已经执行了分步定义的两个步骤(声明并开辟空间),在输出后面去掉“.getInfo()”,则输出结果是一堆内存地址。
范例:静态初始化
package course_2;
class Person { private String name; private int age;
public Person(String name, int age) { this.name = name; this.age = age; }
public String getInfo() { return "姓名:" + this.name + ",年龄:" + this.age; } }
public class StringDemo { public static void main(String args[]) { Person per[] = new Person[] { new Person("张三", 20), new Person("李四", 25), new Person("王五", 30) }; // 开辟3个空间 for (int i = 0; i < per.length; i++) { System.out.println(per[i].getInfo()); } } } |
姓名:张三,年龄:20 姓名:李四,年龄:25 姓名:王五,年龄:30 |
实际对于对象数组的概念一直都在使用,例如:之前的字符串数组(String[])就是一个对象数组,对象数组的表示含义就是表示多个的意思。为了更好理解对象数组的概念,可以参考下面一张以上程序的内存分析图:
下面再通过一个程序完成一个对象数组的应用传递,例如:编写一个方法,可以进行对象数组的反转。
package course_2;
class Person { private String name; private int age;
public Person(String name, int age) { this.name = name; this.age = age; }
public String getInfo() { return "姓名:" + this.name + ",年龄:" + this.age; } }
public class StringDemo { public static void main(String args[]) { Person per[] = new Person[] { new Person("张三", 20), new Person("李四", 25), new Person("王五", 30) }; // 开辟3个空间 reverse(per); // 进行字符串反转 for (int i = 0; i < per.length; i++) { System.out.println(per[i].getInfo()); } }
public static void reverse(Person temp[]) { // 接收的是对象数组 int centern = temp.length / 2; // 取得中间点 int head = 0; int tail = temp.length - 1; for (int i = 0; i < centern; i++) { Person p = temp[head]; temp[head] = temp[tail]; temp[tail] = p; head++; tail--; } } } |
姓名:王五,年龄:30 姓名:李四,年龄:25 姓名:张三,年龄:20 |
此时程序的内存关系图如下:
引用操作的核心就在于地址上的变化,不管如何操作,永远都是一块堆内存被多个栈内存所指向。
package course_2;
class Person { private String name; private int age;
public Person(String name, int age) { this.name = name; this.age = age; }
public String getInfo() { return "姓名:" + this.name + ",年龄:" + this.age; } }
public class StringDemo { public static void main(String args[]) { Person per1[] = new Person[] { new Person("张三", 20), new Person("李四", 25), new Person("王五", 30) }; // 开辟3个空间 Person per2[] = new Person[] { new Person("赵六", 35), new Person("孙七", 40), new Person("王八", 45) }; Person per3[] = new Person[per1.length + per2.length]; System.arraycopy(per1, 0, per3, 0, per1.length); System.arraycopy(per2, 0, per3, per1.length, per2.length); for (int i = 0; i < per3.length; i++) { System.out.println(per3[i].getInfo()); } } } |
姓名:张三,年龄:20 姓名:李四,年龄:25 姓名:王五,年龄:30 姓名:赵六,年龄:35 姓名:孙七,年龄:40 姓名:王八,年龄:45 |
通过代码的分析,可以发现数组的拷贝操作依然可以使用,即:不管是基本数据类型,还是引用数据类型的数组都是一样执行的,但是对于排序操作(java.util.Arrays.sort(per3))就不能使用了!
2.4 对象的比较操作(重点)
要判断一个类的两个对象是否相等,肯定要比较两个对象中的所以属性的内容是否相等,最简单的实现方式如下:
package course_2;
class Person { private String name; private int age;
public Person(String name, int age) { this.name = name; this.age = age; }
public String getName() { return this.name; }
public int getAge() { return this.age; } }
public class StringDemo { public static void main(String args[]) { Person per1 = new Person("张三", 20); Person per2 = new Person("张三", 20); if (per1.getName().equals(per2.getName()) && per1.getAge() == per2.getAge()) { System.out.println("两个对象相等!"); } else { System.out.println("两个对象不相等!"); } } } |
两个对象相等! |
判断两个对象是否相等,实际上是自己的一种功能,但是以上的程序呢?
主方法或者说是主类,实际上在开发中来讲属于客户方(第三方),所谓的客户方指的就是调用程序的一方,所以对于客户端的操作应该越简单越好,那么以上的操作之中是将一些具体功能交给客户端实现了,很明显这样客户端太复杂了,所以现在的代码应该修改。
package course_2;
class Person { private String name; private int age;
public Person(String name, int age) { this.name = name; this.age = age; }
// 当一个类的对象传递到类的内部之后最大的好处在于:可以直接通过对象调用私有操作 public boolean compare(Person per) { // 与指定的对象相比 if (per == null) { return false; } if (per == this) { // 当前对象和传递进来的对象地址相同 return true; // 地址相同,肯定是同一个对象 } if (this.name.equals(per.name) && this.age == per.age) { //这个判断必须保证在实例化对象时设置上属性值(保证this.name非空),否则会出现NullPointerException异常。 return true; } return false; }
public String getName() { return this.name; }
public int getAge() { return this.age; } }
public class StringDemo { public static void main(String args[]) { Person per1 = new Person("张三", 20); Person per2 = new Person("张三", 20); if (per1.compare(per2)) { System.out.println("两个对象相等!"); } else { System.out.println("两个对象不相等!"); } } } |
两个对象相等! |
对象比较的关键有两点:
● 对象比较的操作一定是每一个类自己的功能;
● 一个类可以接收本类的引用,而且接收之后,可以直接通过这个对象调用类中的属性,不再需要使用getter方法,因为此时属于类的内容,内容是可以直接访问私有属性的。
2.5 引用的真实生活应用(重点)
程序来源于生活,只要通过合理的抽象,现实社会的一切都可以通过面向对象的关系分析出来,那么下面做个分析。
范例:要求现在表示出一种概念—— 每个人有一辆车
本程序如果换到了数据表的设计上肯定是一对一的操作关系,那么如果现在不是进行程序的开发,而是进行数据表的创建,则数据库创建脚本如下:
DROP TABLE car PURGE; DROP TABLE member PURGE; CREATE TABLE member ( mid NUMBER PRIMARY KEY, name VARCHAR2(20) NOT NULL ); CREATE TABLE car( mid NUMBER PRFERENCES member (mid), name VARCHAR2(50) NOT NULL ); |
笔记:一对一的关系,应该还要把car表的mid列添加唯一约束吧。
这样的两张表依靠主键进行关联的操作,那么如果现在要进行类的设计呢?则肯定也要准备出两个类。
package course_2;
class Member { private int mid; private String name; private Car car; // 一人有一辆车
public Member(int mid, String name) { this.mid = mid; this.name = name; }
public String getMemberInfo() { return "编号:" + mid + ",姓名:" + name; }
public void setCar(Car car) { this.car = car; }
public Car getCar() { return this.car; } }
class Car { private String name; private Member menber;
public Car(String name) { this.name = name; }
public String getCarInfo() { return "车的名称:" + name; }
public void setMember(Member member) { this.menber = member; }
public Member getMember() { return this.menber; } }
public class StringDemo { public static void main(String args[]) { Member mem = new Member(1, "张三"); Car car = new Car("BMW"); mem.setCar(car); // 一人有一辆车 car.setMember(mem); // 一辆车属于一个人 System.out.println(mem.getMemberInfo()); System.out.println(mem.getCar().getCarInfo()); } } |
编号:1,姓名:张三 车的名称:BMW |
此时就是依靠了程序表示出一对一的操作关系,而且对于以下的代码:
mem.getCar().getCarInfo() |
这种程序在开发中称为“代码链”,中间依靠“. ”进行链接。
在这里就可以无限地循环点:car.getMember().getCar().getMember()…..
如果说现在进一步呢,例如:每一个还有一个孩子,孩子还可能有汽车。
package course_2;
class Member { private int mid; private String name; private Car car; // 一人有一辆车 private Member child; // 一人有一个孩子
public Member(int mid, String name) { this.mid = mid; this.name = name; }
public String getMemberInfo() { return "编号:" + mid + ",姓名:" + name; }
public void setChild(Member child) { this.child = child; }
public Member getChild() { return this.child; }
public void setCar(Car car) { this.car = car; }
public Car getCar() { return this.car; } }
class Car { private String name; private Member menber;
public Car(String name) { this.name = name; }
public String getCarInfo() { return "车的名称:" + name; }
public void setMember(Member member) { this.menber = member; }
public Member getMember() { return this.menber; } }
public class StringDemo { public static void main(String args[]) { Member mem = new Member(1, "张三"); Member chi = new Member(2, "张子"); Car car = new Car("BMW"); Car c = new Car("碰碰车"); mem.setCar(car); // 一人有一辆车 car.setMember(mem); // 一辆车属于一个人 mem.setChild(chi); // 一个人有一个孩子 chi.setCar(c); // 孩子有一辆车 c.setMember(chi); // 一辆车属于一个孩子 System.out.println(mem.getMemberInfo()); System.out.println(mem.getCar().getCarInfo()); System.out.println(mem.getChild().getMemberInfo()); System.out.println(mem.getChild().getCar().getCarInfo()); } } |
编号:1,姓名:张三 车的名称:BMW 编号:2,姓名:张子 车的名称:碰碰车 |
实际上这种人和孩子的关系有点类似于:emp和mgr的关系。
2.6 思考题(核心)
可以使用之前的emp类继续完成开发,而且为了节约时间,可以暂时不写setter、getter
要求表示出scott.emp和scott.dept之间的操作关系,并且编写数据测试,使用的字段:
● scott.emp :empno、ename、job、sal、comm、deptno、mgr;
● scott.dept :deptno、dname、loc;
本程序肯定还是两个类完成,这两个类的关系:
● 雇员和领导:一对一的自身关联;
● 部门雇员:一对多的关联,既然要想表现出多的概念,那么肯定要使用对象数组完成;
DIY: |
package course_2;
class Emp { private int empno; private String ename; private String job; private double sal; private double comm; private Dept dept;
public Emp() { }
public Emp(int empno, String ename, String job, double sal, double comm) { this.setCom(comm); this.setEmpno(empno); this.setEname(ename); this.setJob(job); this.setSal(sal); }
public String getEmpInfo() { return "雇员信息: " + "n" + "t|- 编号: " + this.getEmpno() + "n" + "t|- 姓名: " + this.getEname() + "n" + "t|- 职位: "+ this.getJob() + "n" + "t|- 工资: " + this.getSal() + "n" + "t|- 奖金: " + this.getComm() + "n" + "t|- 月薪: "+ this.salary() + "n" + "t|- 年薪: " + this.income(); }
public double salary() { return sal + comm; }
public double income() { return this.salary() * 12; }
public void setEname(String n) { ename = n; }
public void setEmpno(int n) { empno = n; }
public void setJob(String j) { job = j; }
public void setSal(double s) { sal = s; }
public void setCom(double c) { comm = c; }
public void setDept(Dept dept) { this.dept = dept; }
public Dept getDept() { return this.dept; }
public int getEmpno() { return empno; }
public String getEname() { return ename; }
public String getJob() { return job; }
public double getSal() { return sal; }
public double getComm() { return comm; }
}
class Dept { private String dept; private int deptno; private String loc; private Emp emp;
public Dept(String dept, int deptno, String loc) { this.dept = dept; this.deptno = deptno; this.loc = loc; }
public void setEmp(Emp emp) { this.emp = emp; }
public String getDeptInfo() { return "部门信息:" + "n" + "t|- 部门编号: " + this.deptno + "n" + "t|- 部门名:" + this.dept + "n" + "t|- 位置:" + this.loc; } }
public class Demo { public static void main(String args[]) { Emp emp = new Emp(7369, "SMISH", "CHERK", 800, 10); Dept dept = new Dept("销售部", 14, "北京"); emp.setDept(dept); dept.setEmp(emp); System.out.println(emp.getEmpInfo()); System.out.println(emp.getDept().getDeptInfo()); } } |
雇员信息: |- 编号: 7369 |- 姓名: SMISH |- 职位: CHERK |- 工资: 800.0 |- 奖金: 10.0 |- 月薪: 810.0 |- 年薪: 9720.0 部门信息: |- 部门编号: 14 |- 部门名:销售部 |- 位置:北京 |
Answer: |
package course_2;
class Emp { private int empno; private String ename; private String job; private double sal; private double comm; private Emp mgr; // 每个雇员有一个领导 private Dept dept; // 每个雇员属于一个部门
public Emp() { }
public Emp(int empno, String ename, String job, double sal, double comm) { this.comm = comm; this.empno = empno; this.ename = ename; this.job = job; this.sal = sal; }
public String getEmpInfo() { return "雇员信息: " + "n" + "t|- 编号: " + this.empno + "n" + "t|- 姓名: "+ this.ename + "n" + "t|- 职位: " + this.job + "n"+ "t|- 工资: " + this.sal + "n" + "t|- 奖金: " + this.comm; }
public void setMgr(Emp mgr) { this.mgr = mgr; }
public Emp getMgr() { return this.mgr; }
public void setDept(Dept dept) { this.dept = dept; }
public Dept getDept() { return this.dept; }
}
class Dept { private String dname; private int deptno; private String loc; private Emp[] emps; // 每个部门有多个雇员
public Dept(int deptno, String dname, String loc) { this.dname = dname; this.deptno = deptno; this.loc = loc; }
public void setEmps(Emp[] emps) { this.emps = emps; }
public Emp[] getEmps() { return this.emps; }
public String getDeptInfo() { return "部门信息:" + "n" + "t|- 部门编号: " + this.deptno + "n"+ "t|- 部门名:" + this.dname + "n" + "t|- 位置:" + this.loc; }
}
public class Demo { public static void main(String args[]) { Emp allEmp[] = new Emp[] { new Emp(7369, "SMISH", "CHERK", 800.0, 10), new Emp(7566, "ALLEN", "MANAGER", 2450.0, 100), new Emp(7839, "KING", "PRESIDENT", 5000.0, 0) };
Dept dept = new Dept(10, "ACCOUNT", "New York"); // 先设置雇员和领导的关系 allEmp[0].setMgr(allEmp[1]); allEmp[1].setMgr(allEmp[2]); // 设置雇员和部门的关系,每个雇员都有部门 allEmp[0].setDept(dept); allEmp[1].setDept(dept); allEmp[2].setDept(dept); // 一个部门有多个雇员 dept.setEmps(allEmp); // 信息的输出: System.out.println(dept.getDeptInfo()); System.out.println("部门人数:" + dept.getEmps().length); for (int x = 0; x < dept.getEmps().length; x++) { Emp emp = dept.getEmps()[x]; //注意这个用法 System.out.println(emp.getEmpInfo()); // 也可以用下面这条语句输出: // System.out.println(allEmp[x].getEmpInfo()); if (emp.getMgr() != null) { // 存在领导 System.out.println("他的领导:n" + emp.getMgr().getEmpInfo()); } else { System.out.println("他没领导!"); } System.out.println("-----------------------------"); } } } |
部门信息: |- 部门编号: 10 |- 部门名:ACCOUNT |- 位置:New York 部门人数:3 雇员信息: |- 编号: 7369 |- 姓名: SMISH |- 职位: CHERK |- 工资: 800.0 |- 奖金: 10.0 他的领导: 雇员信息: |- 编号: 7566 |- 姓名: ALLEN |- 职位: MANAGER |- 工资: 2450.0 |- 奖金: 100.0 ----------------------------- 雇员信息: |- 编号: 7566 |- 姓名: ALLEN |- 职位: MANAGER |- 工资: 2450.0 |- 奖金: 100.0 他的领导: 雇员信息: |- 编号: 7839 |- 姓名: KING |- 职位: PRESIDENT |- 工资: 5000.0 |- 奖金: 0.0 ----------------------------- 雇员信息: |- 编号: 7839 |- 姓名: KING |- 职位: PRESIDENT |- 工资: 5000.0 |- 奖金: 0.0 他没领导! ----------------------------- |
对于这样的程序肯定是必须能够分析出来的,而且这种程序是作为日后开发的核心基础所在,不可忽视,通过这样的程序思路,以后可以表示出:
● 一个停车场有多辆汽车,每辆汽车都有一个司机;
● 一个学校有多间教室,每个教室有多套桌椅和多个学生,每个学生有自己使用的桌椅和电脑;
● 一个房间有多扇窗户,一个门,若干个灯所组成;
简单java类表示出的是某一类的信息,但是不同的类之间会存在关系,这种就可以通过引用数据类型来进行表示,如果对于此类思路不明确的,好好完成以上的题目,以后这个思路肯定是重点使用的。
现在通过如上的代码也可以发现一个问题:简单java类和数据表;
● 表名称 = 类名称;
● 表字段 = 类中的属性;
● 表中的每行记录 = 类的每一个对象;
所以简单java类的设计原则就等同与表的原则,就是要进行事务的抽象分析。
2.7 数据结构——简单链表(理解)
对象数组:可以保存一组对象,但是对象数组有一个天生的问题就是其数组的长度是固定的,而在开发之中为了不受对象数组长度的限制,所以引入链表这种数据结构。
所谓的链表程序实际上就是使用节点包装所需要保存的数据。
如果要想完成链表的开发,则首先应该定义出节点的操作类,以保存String型数据为例,可以定义一个Node类;
class Node { private String data; // 要包装的数据 private Node next; // 保存它的下一个节点
public Node(String data) { // Node类的功能一定要包装数据 this.data = data; }
public void setNext(Node next) { this.next = next; }
public Node getNext() { return this.next; }
public String getData() { return this.data; } } |
范例:手工配置节点的关系并输出
public class Demo { public static void main(String args[]) { Node root = new Node("根节点"); Node n1 = new Node("保存数据A"); Node n2 = new Node("保存数据B"); Node n3 = new Node("保存数据C"); Node n4 = new Node("保存数据D"); Node n5 = new Node("保存数据E"); // 下面应该配置这些节点之间的操作关系 root.setNext(n1); n1.setNext(n2); n2.setNext(n3); n3.setNext(n4); n4.setNext(n5); // 假设有多个节点,不知道循环多少次要使用while循环 // 循环的结束条件应该是一个节点如果没有下一个节点 // 如果要输出肯定从根节点开始输出 Node currNode = root; // 找到根节点 while (currNode != null) { // 有节点 System.out.println("数据:" + currNode.getData()); currNode = currNode.getNext(); // 更改当前节点为其下一个节点 } } } |
数据:根节点 数据:保存数据A 数据:保存数据B 数据:保存数据C 数据:保存数据D 数据:保存数据E |
但是以上的输出操作并不是合理的做法,更合理的做法应该使用递归完成输出。
public static void main(String args[]) { Node root = new Node("根节点"); Node n1 = new Node("保存数据A"); Node n2 = new Node("保存数据B"); Node n3 = new Node("保存数据C"); Node n4 = new Node("保存数据D"); Node n5 = new Node("保存数据E"); // 下面应该配置这些节点之间的操作关系 root.setNext(n1); n1.setNext(n2); n2.setNext(n3); n3.setNext(n4); n4.setNext(n5); printNode(root); }
public static void printNode(Node node) { if (node != null) { System.out.println(node.getData()); printNode(node.getNext()); // 找到下一个 } } |
根节点 保存数据A 保存数据B 保存数据C 保存数据D 保存数据E |
以上完成了一个最简单的链表操作,应该可以理解链表中的数据保存形式,可是以上的代码是通过用户手工配置完成的,很明显不可取,用户所关心的肯定只是数据的保存,而对于这些节点的安排用户根本就不需要关心,所以为了可以让程序自动的安排节点,就需要编写一个结点的操作类—— link。
不过是自动完成操作,还是手工完成操作,链表的核心就在于根节点上,肯定第一个保存的数据要作为根节点;
分析过程:
1、第一个保存进来的节点肯定是作为根节点存在,因为所有的操作都要通过根节点展开;
2、第二个节点必须判断根节点是否存在,如果存在则肯定要保存在根节点之后(next),但是这个过程应该由Node类自己进行处理;
3、第三个节点进来之后,肯定要保存在“某一个已经保存的最后一个节点之后,而判断保存位置的最后做法就是,判断某一个当前节点是否是null”。
现在已经实现了数据的增加和输出的功能,那么如何查询一个数据是否存在呢?
● 还应该是从根节点开始查找,而且查找的过程应该交给Node类完成
既然可以进行节点的增加,那么该如何进行节点的删除呢?
对于节点的删除操作要考虑两种情况:
● 情况一:根节点是要删除的节点,把根节点设置为根节点的下一个;
● 情况二:删除的不是根节点而是其他节点,例如,假设要删除的是第二个节点;
package course_2;
class Node { private String data; // 要包装的数据 private Node next; // 保存它的下一个节点
public Node(String data) { // Node类的功能一定要包装数据 this.data = data; }
public void setNext(Node next) { this.next = next; }
public Node getNext() { return this.next; }
public String getData() { return this.data; }
public void addNode(Node newNode) { // 将节点保存在合适的位置上 if (this.next == null) { // 当前节点后没有其他节点 this.next = newNode; // 保存 } else { // 当前节点之后有内容 this.next.addNode(newNode); // 当前节点的下一个节点保存 } }
public void printNode() { System.out.println(this.data); // 输出当前节点的数据 if (this.next != null) { // 还有后面的节点 this.next.printNode(); } }
public boolean containsNode(String data) { if (this.data.equals(data)) { // 当前节点的数据为查找数据 return true; } else { // 当前节点的数据不是查找数据,继续向下 if (this.next != null) { // 现在没有查找到最后的节点 return this.next.containsNode(data); } else { // 后面没有节点 return false; } } }
public void removeNode(Node previous, String data) { if (this.data.equals(data)) { // 当前 节点的数据满足删除 previous.next = this.next; // 空出当前节点 } else { this.next.removeNode(this, data); // 向下继续删除 } } }
class Link { // 表示链表的操作类,主要就是操作Node类 private Node root; // 将根节点定义为类中的属性
public void add(String data) { // 设置要增加的数据 if (data == null) { // 如果没有数据 return; // 返回到被调用处 } Node newNode = new Node(data); // 将数据包装在节点 if (this.root == null) { // 现在没有根节点 this.root = newNode; // 第一个节点作为根节点 } else { // 如果不是根节点,则通过Node类指定保存的位置 this.root.addNode(newNode); } }
public void print() { if (this.root != null) { // 现在 有节点有数据,可以保存 this.root.printNode(); // 输出还是交给Node } }
public boolean contains(String data) { if (data == null || this.root == null) { return false; // 没有内容就不查 } return this.root.containsNode(data);// 交给Node类完成 }
public void remove(String data) { if (this.contains(data)) { // 要删除存在的节点 if (this.root.getData().equals(data)) { // 如果删除的是根节点 this.root = this.root.getNext(); // 根节点的下一个节点为根 } else { // 交给Node类完成 // 从根节点的下一个节点开始,判断要删除的节点 this.root.getNext().removeNode(this.root, data); } } } }
public class Demo { public static void main(String args[]) { Link all = new Link(); all.add("A"); all.add("B"); all.add("C"); all.remove("B"); all.remove("A"); all.print(); System.out.println(all.contains("A")); System.out.println(all.contains("X")); }
} |
C false false |
此时就是完成了一个最简单的链表,在本程序之中,一定要明确的发现各个操作之间的关系,明白Link和Node类之间的操作联系,链表的核心就在于根节点的操作上。
对于链表本程序至少一个简单的单向链表的部分工具,而实际上对于链表还可能有:
● 单向循环链表:最后一个节点指向不是null而是根节点;
● 双向链表:现在的程序只保留下一个节点,而双向链表会保留它的上一个节点;
● 双向循环链表:双方都进行了链接。
本程序实话来讲是一个以后包括面试和一些java类的实现原理,在面试之中经常也会出现类似的题目。
2.8 二叉树(了解)
二叉树(Binary Tree)也是一种比较常见的数据结构,二叉树的存放原则如下:
● 取出第一个数据保存在根节点之中;
● 比根节点数据小的要放在左子树;
● 比根节点数据大的要放在右子树;
而且对于二叉树排序而言,最后还应该按照中序遍历的操作进行输出:左 → 根 → 右;
所以现在要想实现二叉树的关键是必须有一个可以判断大小的操作,如果是普通数字可以直接使用关系运算判断,但是如果保存的是字符串呢?使用compareTo( )方法完成,下面演示一个保存和输出。
不管如何操作,有一点是绝对不会变的,所有的数据结构之中,Node类是必须存在的,因为Node类的功能有两个,一个是包装数据,另外一个是保存下一个节点的引用;
package course_2;
class Node { private String data; // 要包装的数据 private Node left; // 保存左子树 private Node right; // 保存右子树
public Node(String data) { // Node类的功能一定要包装数据 this.data = data; }
public void setLeft(Node left) { this.left = left; }
public void setRight(Node right) { this.right = right; }
public String getData() { return this.data; }
public Node getLeft() { return this.left; }
public Node getRight() { return this.right; }
public void addNode(Node newNode) { // 增加节点 if (newNode.getData().compareTo(this.data) < 0) { // 小于 if (this.left == null) { // left节点没有内容 this.left = newNode; // 保存在左子树 } else { this.left.addNode(newNode); // 向下继续保存 } } else { if (this.right == null) { this.right = newNode; } else { this.right.addNode(newNode); // 保存在右子树 } } }
public void printNode() { if (this.left != null) { // 有左子树 this.left.printNode(); } System.out.println(this.data); if (this.right != null) { this.right.printNode(); } } }
class BinaryTree { // 二叉树 private Node root; // 根节点
public void add(String data) { Node newNode = new Node(data); // 数据都要封装为节点 if (this.root == null) { // 根节点为空 this.root = newNode; // 第一个节点作为根节点 } else { // 应该交给Node类保存在合适的位置上 this.root.addNode(newNode); // 给Node类处理 } }
public void print() { if (this.root != null) { this.root.printNode(); } } }
public class Demo { public static void main(String args[]) { BinaryTree bt = new BinaryTree(); bt.add("B"); bt.add("C"); bt.add("A"); bt.print(); } } |
A B C |
二叉树除了可以保存数据之外,最大的用处是进行排序,但是不管是何种操作,都是根节点的操作,都是Node的保存形式不同而已。
3、总结
1、新知识:this关键字、对象数组;
1) this关键字:
● this属性:表示操作的是当前类中的属性,而且也强调了,只有是类中的属性前面都要加上“this.” ;
● this.方法( ):表示的是类中的操作方法;
● this( ):表示调用类中的构造方法,但是在使用此语句调用的时候一定要留有出口,必须放在构造方法的首行;
● this表示当前对象:当前正在操作类方法的对象,成为当前对象:
2) 对象数组:是包含了多个对象,但是对象数组本身会受到数组长度的限制;
● 对象数组的动态初始化:类名称对象数组名称[ ] = new 类名称 [长度],开辟之后每个内容都是null;
● 对象数组的静态初始化:类名称对象数组名称 [ ] = new 类名称 [ ] {对象1,对象2,…};
● 在使用对象数组的时候,可以进行数组的拷贝,但是排序暂时无法使用;
3) 对象比较:对象比较是一个类本身所具备的一种功能,属于类本身的方法,而且对象的比较需要将每一个属性都进行依次的判断;
2、简单java类的关系指定及与现实生活以及数据表之间的对应关系;
● 类名称 = 表名称;
● 类属性 = 表字段;
● 类对象 = 表的每行记录,对象数组 = 表的多行记录;
● 而且表之间的主外键链接,可以使用引用关系进行表示;
3、对于链表的操作一定要明白其原理,可以自己独立的编写增加和输出两个操作;
4、作业
1、完成如下一个程序:
有一个Person类(name、age属性),要求可以在链表中保存多个Person对象,可以实现增加、输出全部、查询、删除数据;
提示:可以直接参考已经给出的操作程序完成。
本程序的关键有两点:
● 在Node类中所保存的应该是Person对象数组;
● 在Person类中应该提供compare( )方法进行对象的比较;
DIY |
package course_2;
class Person { private String name; private int age; private Person next;
public Person(String name, int age) { this.name = name; this.age = age; }
public String getName() { return name; }
public void setNext(Person next) { this.next = next; }
public Person getNext() { return this.next; }
public void addNode(Person newNode) { if (this.next == null) { this.next = newNode; } else { this.next.addNode(newNode); } }
public void printNode() { System.out.println(this.name + " " + this.age); if (this.next != null) { this.next.printNode(); } }
public boolean containsNode(String name) { if (this.name.equals(name)) { return true; } else { if (this.next != null) { return this.next.containsNode(name); } else { return false; } } }
public void removeNode(Person previous, String name) { if (this.name.equals(name)) { previous.next = this.next; } else { this.next.removeNode(this, name); } } }
class Link { private Person root;
public void add(String name, int age) { Person newNode = new Person(name, age); if (root == null) { this.root = newNode; } else { this.root.addNode(newNode); } }
public void print() { if (root != null) { root.printNode(); } }
public boolean contains(String name) { if (name == null || this.root == null) { return false; } return root.containsNode(name); }
public void remove(String name) { if (this.contains(name)) { if (this.root.getName().equals(name)) { this.root = this.root.getNext(); } else { this.root.getNext().removeNode(this.root, name); } } } }
public class Demo { public static void main(String args[]) { Link li = new Link(); li.add("Alex", 15); li.add("Mary", 22); li.add("Smith", 37); System.out.println(li.contains("Alex")); li.remove("Mary"); li.print(); } } |
true Alex 15 Smith 37 |
Answer |
package course_2;
class Person { private String name; private int age;
// 按照简单java类的要求,应该提供无参,但是本程序为了简便不再写暂时不用的程序 public Person(String name, int age) { this.name = name; this.age = age; }
public void setName(String name) { this.name = name; }
public void setAge(int age) { this.age = age; }
public String getName() { return this.name; }
public int getAge() { return this.age; }
public boolean compare(Person per) { if (per == null) { // 传入的per对象是null return false; // 直接表示不是同一个对象 } if (per == this) { // 比较的是两个对象的地址 return true; // 地址相同肯定是同一个对象 } // 类的对象传回本类之中可以直接通过“对象.属性”操作 if (this.name.equals(per.name) && this.age == per.age) { // 所有属性都依次判断 return true; // 对象内容相等 } else { return false; // 对象内容不相等 } }
public String getPersonInfo() { // 所有的操作返回后输出 return "姓名:" + this.name + ",年龄:" + this.age; } }
class Node { // 表示节点,为了封装数据,并且可以指向下一个节点 private Person data; // 现在要保存的数据是Person类型 private Node next; // 保存下一个节点
public Node(Person data) { // 要进行封装的数据 this.data = data; }
public void setNext(Node next) { this.next = next; }
public Node getNext() { return this.next; }
public Person getData() { return this.data; }
public void addNode(Node newNode) { if (this.next == null) { this.next = newNode; // 保存新的节点 } else { this.next.addNode(newNode); // 向下继续保存 } }
public void printNode() { System.out.println(this.data.getPersonInfo());// 输出当前节点的数据 if (this.next != null) { this.next.printNode(); // 向下继续输出节点 } }
public boolean containsNode(Person data) { if (this.data.compare(data)) { // 当前节点为要查询的节点 return true; } else { if (this.next != null) { return this.next.containsNode(data);// 向下继续查询 } else { return false; // 没有此记录 } } }
public void removeNode(Node previous, Person data) { if (this.data.compare(data)) { // 当前节点为要删除的节点 previous.next = this.next; // 空出当前节点 } else { this.next.removeNode(this, data); } } }
class Link { // 主要的功能是操作链表 private Node root; // 操作的核心在于根节点上
public String print() { if (this.root != null) { // 现在已经存在了根节点 this.root.printNode();// 输出全部的节点 } return "no parameter!"; }
public void add(Person data) { // 增加新的节点数据 if (data == null) { // 增加的数据为空就不增加了 return; } Node newNode = new Node(data);// 将数据封装到节点之中 if (this.root == null) { // 现在不存在根节点 this.root = newNode; // 将新的节点作为根节点出现 } else { // 根节点已经存在,交给节点类自己排序 this.root.addNode(newNode); } }
public boolean contains(Person data) { // 查询数据 if (this.root == null || data == null) { return false; } return this.root.containsNode(data); }
public void remove(Person data) { if (this.contains(data)) { // 要删除的节点存在 if (this.root.getData().compare(data)) { // 根节点为要删除的节点 this.root = this.root.getNext(); } else { this.root.getNext().removeNode(this.root, data); } } } }
public class Demo { public static void main(String args[]) { Link all = new Link(); all.add(new Person("张三", 20)); all.add(new Person("李四", 22)); all.add(new Person("王五", 25)); all.remove(new Person("李四", 22)); all.print(); System.out.println(all.contains(new Person("王五", 25))); System.out.println(all.contains(new Person("王五", 35)));
} } |
姓名:张三,年龄:20 姓名:王五,年龄:25 true false |
本程序虽然完成了,但是也同时可以发现存在以下四个问题:
● 问题一:Node类现在不应该被外部所看见,因为除了Link类之外,Node类基本不关心;
● 问题二:Node类和Link类现在并非是一样的,因为这之间还要使用getter操作;
● 问题三:如果现在节点类中保存的是其他数据,则整个代码都要换;
● 问题四:输出的时候依然需要使用每一个类所独有的方法完成;
本代码只是对链表的概念做了一个基本的铺垫,并没有真正的可以应用在实际的开发之中。
2、熟悉2.5节 ~ 2.6节的代码,多写几遍,并且自己设计一些场景编写;
5、测试题
1、定义一个数组,要求其内容为其下标,并且实现数组的反转功能;
DIY |
public static void main(String args[]) { int data[] = new int[7]; for (int i = 0; i < data.length; i++) { data[i] = i; } for (int i = 0; i < data.length / 2; i++) { int temp = data[i]; data[i] = data[data.length - i - 1]; data[data.length - i - 1] = temp; } for (int i = 0; i < data.length; i++) { System.out.print(data[i] + " "); } } |
6 5 4 3 2 1 0 |
Answer |
public static void main(String args[]) { int data[] = new int[10]; init(data); reverse(data); print(data); }
public static void init(int arr[]) { for (int i = 0; i < arr.length; i++) { arr[i] = i; } }
public static void print(int arr[]) { for (int i = 0; i < arr.length; i++) { System.out.print(arr[i] + " "); } }
public static void reverse(int arr[]) { int center = arr.length / 2; // 求出数组的中间点 int head = 0; // 从头开始据算下标 int tail = arr.length - 1; // 从尾开始计算下标 for (int i = 0; i < center; i++) { int temp = arr[head]; arr[head] = arr[tail]; arr[tail] = temp; } } |
9 1 2 3 4 5 6 7 8 0 |
2、统计出每种工资等级的人数,平均工资、以及此等级的最高和最低工资;
Answer |
SELECT s.grade,s.losal,s.hisal,COUNT(e.empno),AVG(sal) FROM emp e,salgrade s WHERE e.sal between s.losal and s.hisal GROUP BY s.grade,s.losal,s.hisal; |
3、查处所有高于30部门平均工资的雇员姓名、职位、工资、部门名称;
Answer |
SELECT e.ename,e.job,e.sal,d.dname FROM emp e,dept d WHERE e.deptno=d.deptno AND e.sal>( SELECT AVG(sal) FROM emp WHERE deptno=30); |
4、写出Strng类的主要特点(必须熟记);
|- 有两种实例化方式;
1. 直接字符串赋值:在堆内存之中只开辟一块空间,可以自动入池,以备下次继续使用;
2. 通过构造方法完成:会产生两块堆内存空间,不会自动入池,可以使用intern()方法手工入池;
|- 字符串比较:
1. “= =”:比较的是两个字符串所在的堆内存地址的比较,属于数值比较;
2. “equals”:是String类中提供的一个方法,进行内容的比较;
|- 一个字符串常量就是String的匿名对象,是会占堆内存的;
|- 字符串的内容一旦声明之后则不可改变,改变的只是内存地址的指向;
5、写出String类的操作方法(不少于15个)
写清楚方法的返回值类型,参数名称及个数、方法名称。
|- 字符数组和字符串转换:
Ø 【构造】public String(char c[ ]);
Ø 【构造】public String(char c[ ],intoffset,int len);
Ø 【普通】public char[] toCharArray();
Ø 【普通】public char charAt();
|- 字节数组和字符串转换:
Ø 【构造】public String(byte b[ ]);
Ø 【构造】public String(byte b,intoffset,int len);
Ø 【普通】public byte[ ] getBytes();
Ø 【构造】public byte[ ] getBytes(Stringcharset);
|- 字符串拆分:
Ø 【普通】public String[ ] split(Stringregex);
Ø 【普通】public String[ ] split(Strngregex,int size);
|- 字符串比较:
Ø 【普通】public boolean equals(Stringother);
Ø 【普通】public booleaneuqalsIgnoreCase(String other);
Ø 【普通】public int compareTo(Stingstr); → >0、<0、=0
|- 字符串检索:
Ø 【普通】public boolean contains(Stringstr);
Ø 【普通】public int indexOf(String str);
Ø 【普通】public int indexOf(Stringstr,int offset);
Ø 【普通】public int lastIndexOf(Stringstr,);
Ø 【普通】public int lastIndexOf(Stringstr,int offset);
Ø 【普通】public boolean startsWith(Stringstr);
Ø 【普通】public boolean endsWith(Stringstr);
|- 字符串截取:
Ø 【普通】public String substring(intbegin);
Ø 【普通】public String substring(intbegin,int end);
|- 字符串替换:
Ø 【普通】public Sting replaceAll(StingoldStr,Sting newStr);
Ø 【普通】public String replaceFirst(StringoleStr,String newStr)
|- 其他方法
Ø 【普通】public int length();
Ø 【普通】public String trim();
Ø 【普通】public boolean isEmpty();
Ø 【普通】public String toLowerCase(Stringstr);
Ø 【普通】public String toUpperCase(Stringstr);
最后
以上就是无限香水为你收集整理的Java SE 3rd day:Object-oriented 02Java SE 3rd day:Object-oriented 02的全部内容,希望文章能够帮你解决Java SE 3rd day:Object-oriented 02Java SE 3rd day:Object-oriented 02所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复