类与对象

面向对象的设计中更多情况下考虑的是标准的模块化设计,在使用时根据标准进行拼装。

面向过程是面对于一个问题的解决方案,更多情况下不会做出可重用的模块化设计。

面向对象是三个主要特征:

  1. 封装
    内部的操作对外部而言不可见。当内部的操作都不可直接使用时,才是安全的;
  2. 继承
    在已经有的结构的基础上继续进行功能的扩充;
  3. 多态
    范围内可以变化的处理形式;

进行面向对象的程序开发中一般有三个步骤:

  • OOA:面向对象分析
  • OOD:面向对象设计
  • OOP:面向对象编程

设计原则:生活中说得通的场景在程序中也可以说得通的。


类与对象:

类是对某一类事物的共性的抽象概念,对象描述的是一个具体的产物。
如:我和别人进行比较时,可以立刻区分。

所谓人和人的不同依靠的是各自的属性,每一个属性的集合构成了一个群体的定义,这个群体的定义就形成了类。

类是所有对象的共性产物,对象是一个个具有鲜明特征的具体的可以使用的产物。

类是一个模板,对象是类可以使用的实例。

类中有两个组成:成员属性和操作方法。

  • 成员属性;
  • 操作方法:定义对象具有的处理行为;

class 定义类。
使用类,通过对象来调用。如果产生对象,那么必须用如下格式来完成:

  • 声明并实例化对象:类名称 对象名称 = new 类名称();
  • 分步骤完成:
    - 声明对象:类名称 对象名称 = null;
    - 实例化对象:对象名称 = new 类名称();

使用对象操作类:

  • 调用类中的属性:实例化对象.成员属性;
  • 调用类中的方法:实例化对象.方法名称();

例子:

class Person{
String name;
int age;
public void tell(){
System.out.println("姓名:"+name+",年龄:"+age);
}
}

类本身属于引用数据类型,既然是引用数据类型,那么就牵扯到内存的引用传递,引用传递的本质:
同一块堆内存空间,可以被不同的栈内存所指向,也可以更换指向,
范例:定义一个引用传递的分析程序

String 类

所有字符串都要求"“进行定义,同时也利用”+"来进行字符串的连接。
String 类简介:字符串严格意义来讲,不能算是一个基本数据类型。Java里为了方便项目编写,利用其JVM的支持制造了一种可以简单使用的String类,并且可以像基本数据类型一样,进行直接的赋值处理。
(1) String 实例化

public class StringDemo{
public static void main(String[] args){
String str = "www.mldn.cn";
}
}

String类中之所以可以保存字符串,是其中定义了一个数组,也就是String里面字符串中的每一个字符的数据都是保存在了数组之中。
提示–观察String类的源代码实现;D:\Java\jdk-10\lib\src.zip;
JDK1.8版本:以前的String支持类:
1.9及以后的String支持类;
两者支持的数量首先不一样。
从JDK1.9开始,String类中的数组类型采用了byte类型(字节数组),在1.8的String中,String保存的是字符数组。

private final char value[];
private final byte[] value;

字符串就是对数组的一种特殊的包装应用,但是同时也应该清楚:既然包装的是数组,所以字符串中的内容肯定是无法改变的。
在String类里除了可以使用直接赋值的形式未对象进行实例化操作外,还可以按照传统方式,利用构造方法进行实例化的处理。

// public String(String str):
// 利用构造方法来进行实例化
public class StringDemo{
public static void main(String[] args){
String str = new String("www.mldn.cn");
}
}

String本身包装的是一个数组,其有两种对象的实例化形式:直接赋值,和构造方法实例化。


字符串比较:
int型的变量相等,通过"=="来完成。但是String类实际上也牵扯到一个相等的判断问题,但是对于String类相等的判断,也可以使用=,但是不准确。

String strA = "mldn";
String strB = new String("mldn");
System.out.print(strA==strB);

虽然字符串对象的内容是相同的,但是==无法得到准确的判断。这种情况下,如果想实现准确的字符串相等判断,可以使用String类所提供的一个比较方法equals:

strA.eauals(strB);

如果以对象为例,每个对象中都有堆栈的引用。用new的话,两者不是指向同一内存空间,那么栈内保留的地址就不相同。
面试题:String比较重==与equals的区别。

  • == 进行的是数值的比较,如果用于对象的比较,比较的是两个内存的地址数值的比较;
  • equals是类提供的一个比较方法,直接对字符串的内容来进行比较。

字符串常量:

在程序的开发中,任何的整数都是int型,小数都是double。字符串不属于基本数据类型,任何使用的""定义的字符串常量表示的都是String类的匿名对象。

​String stra = "mldn";​​ 画成内存关系图该怎样画:

Java面向对象编程总结_java


所谓的String类对象的直接复制直接描述的是,将一个匿名对象设置一个具体的引用名字。

为什么说字符串是匿名对象?

观察匿名对象的存在:

Java面向对象编程总结_数据_02


如果"mldn"是个匿名对象,那么其一定可以调用equals方法。(true)

此时可以发现:字符串常量可以明确调用equals()方法实现对象相等的判断,从而可以得出:程序中没有字符串的常量,有的只是String类的匿名对象。
整个对象在处理时,完全是系统来帮忙自动进行实例化的。
对象相等判断的小技巧:

  • 以后进行项目开发时:如果现在某些数据是由用户输入,且要求这些数据为一个指定内容的情况下,建议将字符串常量写在前面。
    用户可能不输入数据,没输入数据为空。
    错误写法:

    正确写法:将字符串常量写前面

    equals方法可以自动回避空的判断,如果将字符串的常量写在前面,那么调用eauals()方法不会出现异常。

String类对象两种实例化方式比较:

两种处理模式使用哪种会更好。

  1. 直接赋值的对象实例化模式
    只需要将字符串赋值给String类的对象,就可以实现对象的实例化处理。假设只有一行代码:
    ​​​String str = "mldn";​​​ 只会开出一块堆内存空间。除了这种内存模式之外,利用直接赋值实例化String的形式,还可以实现同一个字符串数据的共享操作。
    观察String直接赋值的数据共享:
  2. Java面向对象编程总结_字符串_03

  3. 此时程序的结果返回的是true。这两个对象所指向的堆内存是同一个,这时的内存关系如图所示:
  4. Java面向对象编程总结_实例化_04

  5. 为什么可以共享呢?
    主要的原因是:在java程序的底层,提供有一个专门的字符串池,字符串数组。既然是数组,数组的内容都是一个个具体的数据。
    在堆内存中存有一个字符串池。当第一次把数据放进的时候,值开始都是为空。
  6. Java面向对象编程总结_数据_05

  7. 当再有一个strB时,会首先去查找池,如果池中有数据,会引用池中的数据。如果没有,会放个新的。
  8. Java面向对象编程总结_java_06

  9. 在采用直接赋值的处理过程之中,对于字符串而言可以实现数据的自动保存,如果再有相同的数据产生时,可以减少对象的产生,以提升操作性能。
  10. 构造方法实例化
    构造方法进行对象实例化,可以说是在进行对象定义时的常见做法。
    此时对于本程序而言,可以通过内存关系图进行观察:
    字符串是一个匿名对象,匿名对象只占据堆内存空间。

    会产生两块堆内存空间,而后只会使用一块,由字符串所定义的匿名对象会成为垃圾空间。
    更换一种形式又会怎样?
    直接赋值的特点在于:可以自动将对象保存到对象池之中。

    除了以上的特点外,在使用构造方法实现String类对象时,不会自动出现保存到字符串池的处理。
    观察构造方法实例化对象时的池操作:

    false。构造方法实例化的对象是自己专用的内存空间,在String类中也提供手工入池的处理情况。
    ​​​public String intern()​​​ 在使用构造方法定义对象之后,由于使用了intern()方法,所以即便是构造出来的String类对象内容,也可以实现池管理,但太啰嗦。
    面试题:解释String类两种对象实例化方式的区别?
  • 直接赋值:只会产生一个实例化对象,并且自动保存到对象池之中,以实现该字符串实例的重用;
  • 构造方法:会产生两个实例化对象,且不会自动入池,无法实现对象重用,但可以利用intern()方法手动的入池处理。

遇到String,用直接赋值的方法最稳妥。


String对象常量池:
对象池的主要目的是实现数据的共享处理,以String的对象池为例,里面的内容主要是为了重用。
对象池可分为两种:

  1. 静态常量池
    指的是程序(.class)在加载时,会自动将此程序之中保存的字符串,普通的常量,类,和方法的信息全部进行分配;
  2. 运行时常量池:当一个程序(*.class)加载后,里面可能有一些变量,这个时候提供的常量池;
    观察一个程序:(静态常量池)

范例:观察一个程序–

Java面向对象编程总结_字符串_07


答案是true。

本程序中所给出的内容都是静态常量数,字符串的常量都是匿名对象。所以最终程序加载后会帮助开发者处理好相应的连接。

一个是加载前,一个是加载后。三个常量相加,这样程序在进行处理时,会指向同样得内存空间。

运行时常量池范例:

Java面向对象编程总结_实例化_08


答案是:false。之所以是false,是因为程序在加载时不确定info是什么内容。因为在进行字符串连接时,info是一个变量,变量得内容是可以修改的,故不认为最终的strB是一个所需要的最终结果。

变量数据即便输入内容一样,也有可能不等。运行时常量池和静态常量池两种。


字符串修改分析

String本质是一个数组,数组的最大缺点是长度不可改变,当设置了一个字符串之后,会自动的进行一个数组空间的开辟,开辟的内容长度是不固定的。

Java面向对象编程总结_实例化_09

字符串的内容一旦定义,不能改变。观察一个程序:

分析下程序的内存处理操作:

String不可修改,栈内存的空间就是str,同时栈内存的内容是’www’。

​String str = "www";​​​ 如果​​str +="mldn.";​

字符串是匿名对象,匿名对象会产生新的空间。指向了新的堆内存空间,会断开一次连接。

Java面向对象编程总结_数据_10


Java面向对象编程总结_字符串_11


充斥着垃圾空间,同时,对象总是在断开和连接过程中不断的进行切换。字符串的内容没有改变,改变的只是引用。

通过此时的程序可以发现,在整个处理过程中,字符串常量的内容并没有发生任何改变,改变的只是字符串的引用,且这种改变将有可能带来大量的垃圾空间。

String类在开发中不要对内容进行频繁修改:

Java面向对象编程总结_实例化_12

主方法组成分析

public:描述的是一个访问权限,主方法是一切的开始点,开始点一定是公共的;
static:java程序的执行是通过类名称完成的,故表示此方法可以通过类直接调用;
void:主方法是一切的起点,起点一开始就没有返回的可能;
main:系统定义好的方法名称;
String args[]:字符串的数组,可以实现程序启动参数的接受;

例子:输出程序的启动参数。

Java面向对象编程总结_字符串_13


在程序执行时可以设置参数,每一个参数之间进行一个空格分隔。

Java面向对象编程总结_java_14


但是千万要记住,如果参数本身拥有空格,那么就需要使用双引号来包装。

Java面向对象编程总结_数据_15


使用这种启动参数实现数据输入的模拟。

String类常用方法

JavaDoc文档简介

只要是项目,就一定会存在String类定义,所以掌握这个类中常用处理方法,对开发者而言非常重要。
JavaDoc:
在以后进行开发过程中,大量使用Java的API文档,这个文档可以通过Oracale在线访问来查看。
知道的包越多,学的越明白。
如果现在要看String类的相关定义,可以打开java.lang这个包。

文档一般都会有翻译版,不要用翻译版。java开发文档没有中文,要习惯阅读英文文档。

字符串与字符数组

String利用了字符数组实现了包装处理,所有方法有构造方法和普通方法两类。

构造方法:
public String(char[] value) 将传入的全部字符数组变成字符串;
public String(char[] value,int offset, int count) 将部分字符数组变成字符串;
普通方法:
char charAt(int index): 获取指定位置的字符;
char[] toCharArray() 将字符串中的数据以字符数组的形式返回;

利用charAt()是可以获取某一个指定索引位置的字符,但是程序之中的索引下标都是从0开始的。在程序语言之中,最早一直强调的是字符串应该使用字符数组进行描述,所以这一操作在String类的方法中也是有所体现的。

范例:实现字符串与字符数组的转换

Java面向对象编程总结_字符串_16


现在假设要做一个验证功能,判断某一个字符串中的数据是否全部由数字所组成。

  • 最好做法是将字符串变为字符数组;
  • 可以判断每一个字符是否在数字的范围之内;(‘0’~‘9’)
  • 如果有一位不是数字则表示验证失败;

    实际开发中,处理终问时使用char类型,因为其可以包含中文数据。

字符串与字节数组

当进行了字符串与字节转换时,其主要目的是为了进行二进制的数据传输,或者进行编码转换。
String String(byte[] bytes) 将全部的字节数组变为字符串;
String String(byte[] bytes, int offset, int length) 将全部的字节数组变为字符串;
public byte[] getBytes() 将字符串转为字节数组;
byte[] getBytes(String charsetName) 编码转换;

字符串比较

equals()方法,注意进行大小写区分。

除了equals之外,还有其他比较方法。

Java面向对象编程总结_java_17

Java面向对象编程总结_数据_18


Java面向对象编程总结_字符串_19


compareTo:会返回一个int数据,有三种取值:大于,小于,等于。

就是做大小比较的。

进行字符串的大小比较–

Java面向对象编程总结_实例化_20


compareTo返回值要记住;

字符串查找

从一个完整的字符串中查找子字符串,一共有如下查找方法:

Java面向对象编程总结_实例化_21


Java面向对象编程总结_字符串_22


Java面向对象编程总结_数据_23


Java面向对象编程总结_数据_24


Java面向对象编程总结_数据_25


例:判断子字符串方法是否存在

Java面向对象编程总结_字符串_26


但是在1.5之后才有的方法。在1.5之前,查询只能用indexOf的方法完成。

判断字符串是否存在–

Java面向对象编程总结_java_27


indexOf是为了进行子字符串位置的查询,可以按照此形式进行索引位置的确定。

indexOf可以由前向后进行查找,也可以由后向前进行查找。

使用lastIndexOf来进行查找:

Java面向对象编程总结_实例化_28


字符串查找也需要判断开头或结尾的操作,判断是否以指定的字符串开头或结尾:

Java面向对象编程总结_数据_29

字符串替换

通过一个指定内容来机械能指定字符串的替换显示。

Java面向对象编程总结_字符串_30

字符串拆分

拆分操作根据指定的字符串或表达式实现字符串拆分,拆分完的数据以数组形式返回。

观察字符串的拆分处理:

Java面向对象编程总结_实例化_31


除了全部拆分外,还可以拆分为指定个数。

Java面向对象编程总结_java_32


拆分时有可能会遇到拆不了的情况,'192.168.2.3’以点拆拆不开。

使用双斜线"\"进行转义:

Java面向对象编程总结_java_33

字符串截取

Java面向对象编程总结_实例化_34


Java面向对象编程总结_字符串_35


Java面向对象编程总结_java_36


有时开始或结束索引往往是通过indexOf计算而来的。

观察截取:

Java面向对象编程总结_java_37


取出张三。

字符串格式化

Java面向对象编程总结_java_38


Java面向对象编程总结_数据_39

其他

Java面向对象编程总结_字符串_40


isEmpty()主要是判断实例化内容,需要在有实例化对象时进行调用。

Java面向对象编程总结_数据_41


在进行数据输入的时候,难保证输入数据无空格,需要对输入的数据进行处理。

Java面向对象编程总结_java_42


在String类中提供大小写转换,但是这种转换特征可以避免非字母的转换。

观察大小写的转换。缺少首字母大写方法。

自定义首字母大写方法:

Java面向对象编程总结_字符串_43