Java(4)面向对象思考(类的设计和String类的详细学习)

目录

一、类的关系

1、关联

2、聚合、组合 

二、程序设计1:设计Course类

三、程序设计2:设计栈类

四、将基本数据类型值作为对象处理 

五、详探String类

1、不可变字符串

2、驻留字符串

3、替换字符串

4、拆分字符串

5、使用模式匹配、替换和拆分(正则表达式)

6、字符串和字符数组之间的转换

7、更灵活的字符串类:StringBuilder类和StringBuffer类

(1)StringBuilder中的构造方法

(2)StringBuilder中修改字符串的构建器方法

(3)StringBuilder中获取其他属性的方法

(4)示例学习:判断回文时忽略非字母或数字的字符

六、编程练习


面向过程和面向对象的程序设计有很大的不同,Java中主要为面向对象进行程序设计,将焦点放在类的设计上。

面向对象的范式将数据和操作方法包含、耦合在一起,从而构成对象。


一、类的关系

通常来讲,类之间的关系包括:关联、聚合、组合、继承

1、关联

关联是描述两个类之间活动的一种二元关系

2、聚合、组合 

聚合是一种特殊的关联形式,它表示两个对象之间的归属关系。如果被聚集对象的存在依赖于聚集对象,则称这两个对象间的关系为组合

(由于聚合和组合关系都以同样的方式用类表示,所以不区分它们)

“继承”在下篇博客总结 


 二、程序设计1:设计Course类

根据上面的UML图,我设计了一个Course类 ,可实现对课程、学生的添加,对学生个数和名字的查询,对课程名字的查询和删除学生操作,以及对Course类进行测试的代码如下:

import java.util.Scanner;
class Course{
    private String courseName;
    private String[] students = new String[100];
    private int numberOfStudent;

    public Course(String courseName){
        this.courseName = courseName;
    }
    public String[] getStudent(){  //返回选这门课的所有学生
        return students;
    }
    public int getNumberOfStudent(){  //返回学生个数
        return numberOfStudent;
    }
    public String getCourseName(){  //返回课程名字
        return courseName;
    }
    public void addStudent(String student){  //从某门课添加一个学生
        students[numberOfStudent] = student;
        numberOfStudent++;
    }
    public void dropStudent(String student){  //从某门课删除一个学生
        //Programming
        //遍历数组找名为student的学生
        for(int i = 0;i < numberOfStudent;i++){
            if(students[i] == student)
            {
                for(int j = i + 1;j < numberOfStudent;i++,j++)
                {
                    //将后边的学生向前移动一位
                    students[i] = students[j];
                }
                break;
            }
        }
        numberOfStudent--;
    }
}

public class TestCourse { //测试类
    public static void main(String[] args){
        Course course1 = new Course("Data structures");
        Course course2 = new Course("Database Systems");

        course1.addStudent("Peter");
        course1.addStudent("Jim");
        course1.addStudent("Anne");

        course2.addStudent("Peter");
        course2.addStudent("Steve");
        course2.addStudent("Meredith");
        course2.addStudent("Mike");

        //1 第一门课程
        System.out.println("The course1's name is: " + course1.getCourseName());
        System.out.println("Number of students in course1: " + course1.getNumberOfStudent());
        //getStudent course1
        String[] students = course1.getStudent();
        for(int i = 0; i < course1.getNumberOfStudent(); i++){
            System.out.print(students[i]);
            if(i!=course1.getNumberOfStudent()-1)
            {
                System.out.print(", ");
            }
        }

        System.out.println( );

        //2 第二门课程
        System.out.println("The course2's name is: " + course2.getCourseName());
        System.out.println("Number of students in course2: " + course2.getNumberOfStudent());
        //getStudent course2
        String[] studentss = course2.getStudent();
        for(int i = 0; i < course2.getNumberOfStudent(); i++){
            System.out.print(students[i]);
            if(i!=course2.getNumberOfStudent()-1)
            {
                System.out.print(", ");
            }
        }

        System.out.println( );

        //3 删除学生
        System.out.println("delete someone now ? (1:yes  0:no)");
        Scanner input = new Scanner(System.in);
        int INPUT = input.nextInt();
        if(INPUT == 1)
        {
            course2.dropStudent("Meredith");
            System.out.println("The course2's name is: " + course2.getCourseName());
            System.out.println("Number of students in course2: " + course2.getNumberOfStudent());
            //getStudent course2
            String[] studentsss = course2.getStudent();
            for(int i = 0; i < course2.getNumberOfStudent(); i++){
                System.out.print(students[i]);
                if(i!=course2.getNumberOfStudent()-1)
                {
                    System.out.print(", ");
                }
            }
        }

    }
}

/*
The course1's name is: Data structures
Number of students in course1: 3
Peter, Jim, Anne
The course2's name is: Database Systems
Number of students in course2: 4
Peter, Jim, Anne, null
delete someone now ? (1:yes  0:no)
1
The course2's name is: Database Systems
Number of students in course2: 3
Peter, Jim, Anne
*/

三、程序设计2:设计栈类

根据上面的UML图对栈类进行实现,过程中微难点在于push的实现以及StackOfIntegers构建默认容量为16的空栈部分

class StackOfIntegers{
    private int[] elements;  //栈中元素存储
    private int size;
    public static final int DEFAULT_CAPACITY = 16; //final关键字表示不能更改

    // 构建一个默认容量为16的空栈
    public StackOfIntegers(){
        //elements = new int[16];
        this(DEFAULT_CAPACITY);
    }

    // 构建一个指定容量的空栈
    public StackOfIntegers(int capacity){
        elements = new int[capacity];
    }

    // 如果栈为空返回true
    public boolean empty(){
        /*
        if(size == 0){
            return true;
        }else return false;
        */
        return size == 0;
    }

    // 返回栈中元素个数
    public int getSize(){
        return size;
    }

    // 将一个整数存到栈顶
    public void push(int value){
        if( size >= elements.length ){ // 如果栈满
            int[] temp = new int[elements.length * 2];  // 创建一个当前容量二倍的新数组
            System.arraycopy(elements, 0, temp, 0, elements.length); // 将当前数组内容复制到新数组中
            elements = temp;  // 将新数组的引用赋值给栈中当前数组
        }
        elements[size++] = value; // 添加新值
    }

    // 返回栈顶的整数而不从栈中删除它
    public int peek(){
        return elements[size];
    }

    // 删除栈顶整数并返回它
    public int pop(){
        /*
        int num = elements[size];
        elements[size] = 0;
        return num;
        */
        return elements[--size];
    }
}

//Test
public class TestStackOfIntegers {
    public static void main(String[] args){
        StackOfIntegers stack = new StackOfIntegers();

        for(int i = 0; i < 10; i++){
            stack.push(i);
        }
        while(!stack.empty()){
            System.out.print(stack.pop() + " ");
        }
    }
}
/* 9 8 7 6 5 4 3 2 1 0 */

四、将基本数据类型值作为对象处理 

出于对性能的考虑,Java中基本数据类型不作为对象使用,但我们可以将基本数据类型包装成对象java.lang包中为基本数据类型们提供了相对应的包装类。通过使用包装类,可以将基本数据类型值当作对象处理。 

例子:java.lang.Integer类和java.lang.Double类

 以Integer为研究对象:

  • MAX_VALUE和MIN_VALUE表示该类型下的最大最小值
  • 1红色框部分是Integer类
  • 2黄色框部分是数据类型之间的转换
  • compareTo方法比较两个数值,相同返回0,大于返回1,小于返回-1
  • 3绿色框部分的方法是将值转为字符串形式
  • 4蓝色框部分的方法是将数值型字符串转化为数值(radix表示进制)

如果想要表示任意大小的数字,可以使用java.math包中的BigInteger类和BigDecimal类BigInteger类可以表示任意大小的整数,而BigDecimal类可以达到任意精度


五、详探String类

1、不可变字符串

String对象是不可变的,其内容不可更改假如有以下代码:

String s = "Java";
s = "HTML";

此时如果输出s,答案是HTML,但这并不代表着第二行的语句改变了字符串的内容。我们可以理解为数组引用值,第二行的语句只是创建了一个“HTML”的新对象,并将其引用赋值给了s,而第一行创建的“Java”依旧存在,只是不能访问它了,而并非将“Java”修改为了“HTML”。

 

2、驻留字符串

Java对具有相同字符序列的字符串字面值使用同一个实例,例如下面:

String s1 = "lalalalala";
String s2 = new String("lalalalala");
String s3 = "lalalalala";

System.out.println("s1 == s2 is " + (s1 == s2));
System.out.println("s1 == s3 is " + (s1 == s3));

/*
s1 == s2 is false
s1 == s3 is true
*/

s1和s2不同的原因是虽然它们的内容相同,但它们是不同的字符串对象。 

3、替换字符串

虽说一旦创建了字符串其内容就不能改变,但我们可以使用replace、replaceFirst、replaceAll来返回一个源于原始字符串的新字符串。

 4、拆分字符串

split方法可以用指定的分隔符从字符串中提取标记。比如:

String[] s = "lalalala#yeyeyeye#hahahaha".split("#");
for(int i = 0; i < s.length; i++)
{
    System.out.print(s[i] + " ");
}

/*
lalalala yeyeyeye hahahaha
*/

5、使用模式匹配、替换和拆分(正则表达式)

String类中的equals方法用于比较两个字符串是否相同,而功能更强大的matches方法用于检测字符串是否匹配给定的正则表达式。下面的语句均为true:

“Java is fun”.matches("Java.*");
“Java is cool”.matches("Java.*");
“Java is powerful”.matches("Java.*");

/*
true
true
true
*/

“Java.*”是一个正则表达式,它描述的字符串模式是从“Java”开始,后面可以紧跟任意字符

“440-33-2867”.matcher(“\\d{3}-\\{2}-\\{4}”);

/*true*/

上面的\\d表示单个数字\\d{3}表示三个数字

String s = "a+b&$c".replaceAll("[&#+]","NNN"); //一定要有[]符号,否则替换无效!
System.out.print(s);

/*
aNNNbNNNNNNc
*/

上面正则表达式[&#+]指定匹配替换为NNN 

6、字符串和字符数组之间的转换

  • 串-->数组:toCharArray方法(Double.parseDpuble()方法转换值)
char[] chars = "Java".toCharArray();
  • 数组-->串:构造方法String(char[ ]) valueOf(char[ ])方法
String str = new String(new char[]{"J","a","v","a"});
//或
String str = String.valueOf(new char[]{"J","a","v","a"});

7、更灵活的字符串类:StringBuilder类和StringBuffer类

java.lang包中的StringBuilder类和StringBuffer类和String类的区别在于前面提到的:String对象一经创建就无法修改,而这两个类的对象可以对其进行任意修改

例子如下:

public class Test {
    public static void main(String[] args){
        String s = "Java"; //String对象
        StringBuilder sb = new StringBuilder(s); //StringBuilder对象
        change(s, sb);

        System.out.println(s); //输出结果:Java
        System.out.println(sb); //输出结果:Java and HTML
    }

    public static void change(String s, StringBuilder sb){
        s = s + " and HTML";
        sb.append(" and HTML");
    }
}

至于StringBuilder类和StringBuffer类的不同在于,StringBuilder适合单任务访问,而StringBuffer适合多任务并发访问。下面先拿StringBuilder开刀:

(1)StringBuilder中的构造方法

(2)StringBuilder中修改字符串的构建器方法

  1. append方法:追加
  2. delete方法:删除
  3. insert方法:插入
  4. replace方法:替换
  5. reverse方法:倒置
  6. setCharAt方法:设新

注意:如果一个字符串不需要任何改变,则使用String而不用StringBuilder,因为string更高效。

(3)StringBuilder中获取其他属性的方法

(4)示例学习:判断回文时忽略非字母或数字的字符

以下程序在判断回文的时候多加了一个功能:就是忽略掉非字母和数字的部分再进行判断。

import java.util.Scanner;

public class PalindromeIgnore {
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        System.out.println("Enter a string : ");
        String s = input.nextLine();

        System.out.println("忽略非字母或数字字符 \n " + s + " 是回文吗?: " + isPalindrome(s));
    }

    public static boolean isPalindrome(String s){
        String s1 = filter(s);
        String s2 = reverse(s1);
        return s2.equals(s1);
    }

    public static String filter(String s){  //逐一检查字符串s中的每个字符,如果字符是数字或字母,就将其复制到字符串构建器中

        StringBuilder stringBuilder = new StringBuilder();
        for(int i = 0;i < s.length();i++)
        {
            if(Character.isLetterOrDigit(s.charAt(i))){ //用Character类中的isLetterOrDigit方法判断字符是否为数字或字母
                stringBuilder.append(s.charAt(i)); //为真值-->复制字符到新字符串中
            }
        }
        return stringBuilder.toString();
    }

    public static String reverse(String s){  //倒置字符串
        StringBuilder stringBuilder = new StringBuilder(s);
        stringBuilder.reverse();
        return stringBuilder.toString();
    }
}

先构造一个filter方法对字符串进行遍历检查,方法中使用Character类中的isLetterOrDigit方法对字符串(charAt(i)方法返回下标为i的字符)进行判断,如果是数字或字母,则复制到新的字符串s1中。

接下来使用reverse方法对字符串s1进行倒置操作得到新字符串s2,最后使用equals方法对s1和s2进行对比。如果相同,则为回文。 


六、编程练习 

本节学完对面向对象的概念又有了一层次的了解,编程题主要考究对类的设计

代码实现如下:

public class MyInteger {
    private int value;

    public MyInteger(int value){
        this.value = value;
    }

    public int getValue(){
        return value;
    }

    public boolean isEven(){
        return value % 2 ==0;
    }
    public boolean isOdd(){
        return !isEven();
    }
    public boolean isPrime(){
        if(value == 0 || value == 1){
            return false;
        }
        for(int i = 2;i < this.value;i++){
            if(value % i == 0){
                return false;
            }
        }
        return true;
    }

    public static boolean isEven(int value){
        return new MyInteger(value).isEven();
    }
    public static boolean isOdd(int value){
        return new MyInteger(value).isOdd();
    }
    public static boolean isPrime(int value){
        return new MyInteger(value).isPrime();
    }

    public static boolean isEven(MyInteger myInteger){
        return myInteger.isEven();
    }
    public static boolean isOdd(MyInteger myInteger){
        return myInteger.isOdd();
    }
    public static boolean isPrime(MyInteger myInteger){
        return myInteger.isPrime();
    }

    public boolean equals(int value){
        return this.value == value;
    }
    public boolean equals(MyInteger myInteger){
        return this.equals(myInteger.value);
    }

    public static int parseInt(char[] chars){
        String string = new String(chars);
        return Integer.parseInt(string);
    }

    public static int parseInt(String string){
        return Integer.parseInt(string);
    }
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

颜 然

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值