main
入口方法都是类的方法,它是一个纯粹的面向对象的语言,因此面向对象在java学习中是没法绕过的,那既然绕不过,就先干掉他,在适应了它的规则后再深刻了解它。
说到类,其实如今作前端的同窗也会很熟悉,若是你使用过TypeScript,那应该对类的概念就更清楚不过了,这里不对类和对象的概念再作无心义的描述,让咱们直接开始coding,复习
一下类和对象的基本使用方法。html
因为没有很好的想法,那就创造一个接近实际的需求,咱们来用收货地址
来熟悉类和对象基本使用前端
根据上一篇文章中建立的java项目,咱们在src下建立一个包learning.oop
,而后在里面建立一个Class文件DiliveryAddress
,注意类名最好大写开头,驼峰结构命名,idea会自动帮咱们建立与Class文件名相同的类,文件名与类名保持一致。java
package learning.oop;
public class DeliveryAddress {
}
复制代码
好了,如今该想一想里面应该设计什么字段了。我就直接提供了:c++
你是否露出了惊讶的表情,长大了嘴巴,心想,不就是个例子嘛,要不要这么认真,举个猫狗动物的例子它不香吗?要搞这么多字段的东西。(请合拢你张大的嘴巴),咱们不是儿戏,咱们要经过接近真实的东西快速上手java。git
在类中,咱们能够包含仅表示数据的属性以及操做数据的方法,对于表示数据的属性,尽可能使用private
关键字,不要把属性直接暴露出去,若是你有修改和获取数据的需求,则应该使用修改器setter
和获取器getter
的方式来进行。github
接下来先根据上述需求,来建立类中的属性,设计过程当中想一想它应该是哪一种数据类型spring
import java.util.Date;
public class DeliveryAddress {
private Integer id;
private Integer userId;
private String receiverName;
private String receiverPhone;
private String receiverProvince;
private String receiverCity;
private String receiverDistrict;
private String receiverAddress;
private String receiverZip;
private Boolean isDefault;
private Date createTime;
private Date updateTime;
}
复制代码
以上,咱们使用了四种数据类型,分别是Integer
,String
,Boolean
,Date
类型,Date类型引入了一个java.util.Date
的包,说明它是那个包中所定义的一种类,并非基础的数据类型。其余类型也很容易认,认真观察这些类型都是大写开头,因此他们本质也是一种类,这种形式叫作包装类。说到包装了类,有些包装类还对应有基础类型(好比int Interger均可以定义整数)。windows
好比int类型为整型(定义整数用的),他是定义整数变量的基本类型,对应的Interger是它的包装类,定义的是一种对象,纯粹定义的数字能够理解为就是一种数字,可是数字要想使用一些例如toString()
的方法,就要借助对象,因此就会进行Integer类型的包装,若是用int定义的变量,在使用方法的时候java会自动帮咱们进行包装,在java中这种转变叫作自动装箱,说到这里,若是用int变量接收一个Interger定义的变量,java就会自动拆除变量的方法,让他变成一个纯数字,在java中这种转变就是自动装箱(手动拆箱装箱本身理解咯)。后端
若是想详细了解java中的变量,能够自行查阅资料,但更建议的是边学边记。这里就再也不作拓展(好吧,是由于我会的也很少)。api
既然是前端者的后端之旅,那么你们对JavaScript的构造函数必定不会陌生,它是经过constructor
进行定义的,java不一样于此,是经过与类名相同的方法来进行构造函数的定义的,若是咱们不定义构造函数,系统会默认给咱们添加一个没有参数且函数体为空的构造函数,固然咱们也能够自定义带参数的构造函数。
package learning.oop;
import java.util.Date;
public class DeliveryAddress {
private Integer id;
private Integer userId;
private String receiverName;
private String receiverPhone;
private String receiverProvince;
private String receiverCity;
private String receiverDistrict;
private String receiverAddress;
private String receiverZip;
private Boolean isDefault;
private Date createTime;
private Date updateTime;
// 无参构造函数
public DeliveryAddress(){
this.createTime = new Date();
}
public Date getCreateTime() {
return createTime;
}
}
复制代码
这里添加了一个无惨构造函数,里面对createTime作了初始化操做,由于这个属性应该是不能够改变的,并且是在建立对象时候就应该拥有值的。下面还定义了一个public
方法,类型为Date,返回createTime,注意构造函数和getCreateTime中的写法,一个带this,一个不带,两种形式均可以。
tips
注意构造函数也要加public
修饰符
如今咱们去src下的Main方法里面实例化几个对象试试看。
import learning.oop.DeliveryAddress;
public class Main {
public static void main(String[] args) {
DeliveryAddress address1 = new DeliveryAddress();
System.out.println(address1);
System.out.println(address1.toString());
System.out.println(address1.getClass());
System.out.println(address1.getCreateTime());
System.out.println(address1.getCreateTime().getTime());
}
}
复制代码
我打印了其中的toString()
和getClass()
方法的运行结果,toString()
与JavaScript中的方法相似,在咱们呢直接打印这个变量的时候,就会输出它的toString()
结果,所以咱们能够看到直接打印与打印toString()
结果相同,而后好奇打印了getClass()
,获得了这个对象对应的类所在具体地址(包名)learning.oop.DeliveryAddress
经过getCreateTime()
方法,咱们也成功得到了对象建立的时间,,这个createTime实际上是个Date类型的对象,咱们能够经过它上面的方法获取本身想要的时间形式,例如想要时间戳,能够经过getTime()
方法获取。
你们能够经过文档看看Date类定义了哪些方法。其实彻底不用所有看,本身须要用哪些就看哪些。
what?构造函数能够添加多个?使得没错,在C++/Java中都是能够的,这种特色叫作重载,TypeScript中也支持重载,但因为它自己仍是由JavaScript写的,因此它的重载并非真正的重载。
public DeliveryAddress( Integer userId, String receiverName, String receiverPhone, String receiverProvince, String receiverCity, String receiverDistrict, String receiverAddress, String receiverZip ) {
this.userId = userId;
this.receiverName = receiverName;
this.receiverPhone = receiverPhone;
this.receiverProvince = receiverProvince;
this.receiverCity = receiverCity;
this.receiverDistrict = receiverDistrict;
this.receiverAddress = receiverAddress;
this.receiverZip = receiverZip;
this.isDefault = false;
}
public DeliveryAddress( Integer userId, String receiverName, String receiverPhone, String receiverProvince, String receiverCity, String receiverDistrict, String receiverAddress, String receiverZip, Boolean isDefault ) {
this.userId = userId;
this.receiverName = receiverName;
this.receiverPhone = receiverPhone;
this.receiverProvince = receiverProvince;
this.receiverCity = receiverCity;
this.receiverDistrict = receiverDistrict;
this.receiverAddress = receiverAddress;
this.receiverZip = receiverZip;
this.isDefault = isDefault;
}
复制代码
此次我添加了两个带参的构造方法,他们的惟一不一样就在于isDefault
属性的设置,由于java不支持设置默认参数,因此只能用重载的形式来进行设置。同时仔细观察这里的全部属性设置都会使用this.xxx = xxx
,而没有直接使用xxx = xxx
,后者实际上是错误的,这样java分辨不出来你到底要给谁设置值,因此若是属性名跟参数名相同,那就必须加this
。
咱们能够去Main方法中添加两个实例试试
import learning.oop.DeliveryAddress;
public class Main {
public static void main(String[] args) {
DeliveryAddress address1 = new DeliveryAddress();
DeliveryAddress defaultAddress = new DeliveryAddress(
1,
"张三",
"13122888888",
"上海",
"上海",
"浦东新区",
"XX小区XX楼XX户",
"20000",
true
);
DeliveryAddress address2 = new DeliveryAddress(
1,
"张三",
"13122888888",
"上海",
"上海",
"浦东新区",
"XX小区XX楼XX户",
"20000",
);
System.out.println(address1.getCreateTime());
System.out.println(defaultAddress.getCreateTime());
System.out.println(address2.getCreateTime());
}
}
复制代码
咱们打印了三个地址的建立时间,但一看,彷佛不对啊,为何后面两个是null,难道不该该是正常时间?
这实际上是正常现象,三个构造方法是独立的,后两个调用的时候并无去设置时间,因此不会有。
好吧,这真的是故意的,但又一点不是故意的我忘记重写toString()方法了,那么下面咱们来解决这些问题,同时两个带参的构造函数彷佛很大一部分代码是重复的,咱们也顺手将代码重复的问题进行解决。
改良
...
private static int counter = 0;
public DeliveryAddress(){
this.id = DeliveryAddress.counter;
DeliveryAddress.counter++;
this.createTime = new Date();
this.updateTime = this.createTime;
}
public DeliveryAddress( Integer userId, String receiverName, String receiverPhone, String receiverProvince, String receiverCity, String receiverDistrict, String receiverAddress, String receiverZip ) {
this();
this.userId = userId;
this.receiverName = receiverName;
this.receiverPhone = receiverPhone;
this.receiverProvince = receiverProvince;
this.receiverCity = receiverCity;
this.receiverDistrict = receiverDistrict;
this.receiverAddress = receiverAddress;
this.receiverZip = receiverZip;
this.isDefault = false;
}
public DeliveryAddress( Integer userId, String receiverName, String receiverPhone, String receiverProvince, String receiverCity, String receiverDistrict, String receiverAddress, String receiverZip, Boolean isDefault ) {
this(
userId,
receiverName,
receiverPhone,
receiverProvince,
receiverCity,
receiverDistrict,
receiverAddress,
receiverZip
);
this.isDefault = isDefault;
}
@Override
public String toString() {
String res = "id: " + this.id + "\n" +
"userId: " + this.userId + "\n" +
"receiverName: " + this.receiverName + "\n" +
"receiverPhone: " + this.receiverPhone + "\n" +
"receiverCity: " + this.receiverCity + "\n" +
"receiverDistrict: " + this.receiverDistrict + "\n" +
"receiverAddress: " + this.receiverAddress + "\n" +
"receiverZip: " + this.receiverZip + "\n" +
"isDefault: " + this.isDefault + "\n";
return res;
}
复制代码
这里咱们仍是三个构造方法,第一个无惨,后两个有参,第三个比第二个多个isDeafult,这些都没问题,前面提出的问题咱们又是怎么解决的呢?咱们经过给第二个构造函数添加this()
,这表明若是要执行第二个构造方法,就会先执行第一个,给第三个构造方法添加了个this(xxxxx)
里面传进了不少参数,这表明要使用第三个构造方法,就必须调用第二个,同时,也作到了代码的简化,第三个构造函数仅仅是比第二个多了个isDefault
的参数而已,其余代码同样,那就直接调用第二个就行了。
最后实现了个publish String toString()
方法,这个方法奇怪的地方是在它头上多了个@Override
的东西,这个东西叫作注解,能够暂时理解为要重写方法,就必须用这个注解进行标识(实际上是由于我也不会注解,后面再研究好了)。
tips
这里注意一下又添加了一个属性,private static int counter = 0
,这个属性与其余不一样的在于多了个static
关键词的描述,而且直接初始化为0,添加了static
的属性与JavaScript中的做用同样,它就变成了类的属性,而不是某个实例的属性,这里经过它模拟了收货地址id的自增。固然,也可使用static
建立静态方法,它也是属于类的方法,既能够经过类名调用,也能够经过实例进行调用。
而后咱们能够回去Main方法中完善一下三个实例的输出
import learning.oop.DeliveryAddress;
public class Main {
public static void main(String[] args) {
DeliveryAddress address1 = new DeliveryAddress();
DeliveryAddress defaultAddress = new DeliveryAddress(
1,
"张三",
"13122888888",
"上海",
"上海",
"浦东新区",
"XX小区XX楼XX户",
"20000",
true
);
DeliveryAddress address2 = new DeliveryAddress(
1,
"张三",
"13122888888",
"上海",
"上海",
"浦东新区",
"XX小区XX楼XX户",
"20000"
);
System.out.println(address1.getCreateTime());
System.out.println(defaultAddress.getCreateTime());
System.out.println(address2.getCreateTime());
System.out.println(address1);
System.out.println(defaultAddress);
System.out.println(address2);
}
}
复制代码
此次就成功看到了三个建立时间的输出,而且看到直接打印对象,打印出了咱们toString()
方法返回的值。也证实以前说的直接打印对象其实输出的就是toString()
。
在上面运行结果中咱们看到第一个地址的不少属性值都是null,这明显是不行的,若是这些属性没有被赋值,咱们须要给他们添加默认值,添加默认值有两种方式:
private static int counter = 0
同样,只不过普通属性不加staticcreateTime
同样放在无惨构造函数里进行初始化这里我将其完善一下,使用第一种方式进行初始化。
private Integer id;
private Integer userId = -1;
private String receiverName = "";
private String receiverPhone = "";
private String receiverProvince = "";
private String receiverCity = "";
private String receiverDistrict = "";
private String receiverAddress = "";
private String receiverZip = "";
private Boolean isDefault = false;
private Date createTime;
private Date updateTime;
private static int counter = 0;
复制代码
回到Main函数从新运行代码结果为
这样就舒服多了,未填的值直接为设置的初始值。
以上全部的属性,构造方法,普通方法都是咱们本身写的,其实彻底没有必要让本身这么累,idea工具能够帮助咱们作这些事,右键点击idea写代码的区域,点击generate
,或者按相应的快捷键,generate
选项右边有快捷键标识,Mac的是⌘+N
,windows自行查看(个人win懒得开机😂)
经过这些选项,能够自行生成getter
setter
构造函数
toString()
等方法,这里你们自行体验,我也去体验一把。
所谓的getter
就是获取私有属性的方法,setter
就是设置私有属性的方法,由于他们的书写只是体力活,因此你们能够用idea工具生成,若是有须要更改的再去更改。
本篇文章简单介绍了java中类的使用,包括构造方法,构造方法的重载,调用其余构造方法,toString()方法,属性值设置等,而且里面穿插了包装类,拆箱装箱等小知识点。
固然,本文知识java面向对象的开始,由于java总体都是面向对象的,后续将继续分享接口、继承反射、bean、泛型、注解、等内容,尽可能让快速掌握可使用spring boot的程度,而后再补充java的其余知识。有一点要保证的是,这些内容加起来确定不会像字典同样厚,但关键内容仍然会保证不缺失。