文章目录
了解类与对象
前言
Java是一门面向对象编程的语言(OOP),注重的是对象。就像我揍你,只关心我和你两个对象,至于具体用拳头还是用棍子,是左勾拳还是右勾拳,这些都不重要。打人,是我这个对象所具有的功能,在创建我的时候就考虑好了。
这也说明,如果是面向对象,就是找对象,建立对象,发现对象之间的逻辑关系。
面向过程与面向对象的优缺点:
小编在看了zhihu大佬的一篇博客解释的非常通俗易懂,分享给大家
用面向过程的方法写出来的程序是一份蛋炒饭,而用面向对象写出来的程序是一份盖浇饭。
蛋炒饭制作的细节不说了,最后的一道工序肯定是把米饭和鸡蛋混在一起炒匀。盖浇饭呢,则是把米饭和盖菜分别做好,你如果要一份红烧肉盖饭呢,就给你浇一份红烧肉;如果要一份青椒土豆盖浇饭,就给浇一份青椒土豆丝。
蛋炒饭的好处就是入味均匀,吃起来香。如果恰巧你不爱吃鸡蛋,只爱吃青菜的话,那么唯一的办法就是全部倒掉,重新做一份青菜炒饭了。盖浇饭就没这么多麻烦,你只需要把上面的盖菜拨掉,更换一份盖菜就可以了。盖浇饭的缺点是入味不均,可能没有蛋炒饭那么香。
到底是蛋炒饭好还是盖浇饭好呢?其实这类问题都很难回答,非要比个上下高低的话,就必须设定一个场景,否则只能说是各有所长。如果大家都不是美食家,没那么多讲究,那么从饭馆角度来讲的话,做盖浇饭显然比蛋炒饭更有优势,他可以组合出来任意多的组合,而且不会浪费。
盖浇饭的好处就是‘’菜”“饭”分离,从而提高了制作盖浇饭的灵活性。饭不满意就换饭,菜不满意换菜。用软件工程的专业术语就是”可维护性“比较好,”饭” 和”菜”的耦合度比较低。蛋炒饭将”蛋”“饭”搅和在一起,想换”蛋”“饭”中任何一种都很困难,耦合度很高,以至于”可维护性”比较差。软件工程追求的目标之一就是可维护性,可维护性主要表现在3个方面:可理解性、可测试性和可修改性。面向对象的好处之一就是显著的改善了软件系统的可维护性。
一. 类:对象的蓝图
可以理解为现实世界中抽象的事物,它包含着一些已知事物和可执行动作。
类是对象的特征提取,是对象的模型,这一点也是在设计类的时候所需要注意的。
二. 对象:类的实例化
对象的已知事物是实例变量,有不同类型,变量也有很多叫法:字段/属性/成员变量。他们定义在类的内部,方法的外部。忘了说,方法就是可执行动作。
举一个例子:如果有中国人这个类,它有一些属性:姓名、性别、发色、肤色、等等。这些属性你可以在创建类的时候就定义好,比如黑头发、黄皮肤。姓名每个人不同,有默认值,这个后面会讲。你就可以通过 中国人 这个类来实例化一个个对象:张三、李四、王二啥的。
1. 一起来创建对象
基本方法:
class Chinese {
public String name;
public String sex;
public int age;
public void life() {
System.out.println("吃饭、睡觉、打豆豆");
}
}
public class Learning {
public static void main(String[] args) {
Chinese p = new Chinese();
p.name = "李四";
p.sex = "man";
p.age = 10;
System.out.println(p.name);
System.out.println("年龄:" + p.age);
System.out.println(p.sex);
p.life();
}
}
结果:
这里对成员变量都进行了赋值,如果没有初始化,引用类型默认为null,简单类型默认为0值。有两个特殊:char类型默认为’\u000’,boolean类型默认为false。
2. 代码解释
class Chinese 就是创建了一个类,类里面定义了很多属性和life方法
Chinese p = new Chinese() 是实例化,得到p这个对象
对象.属性,是使用的语法,既可以读,也可以写
p.name = "李四"是在写入
System.out.println(p.name)是读取了name并且打印
三. static关键字
1.静态成员变量
静态成员变量也叫做类变量
这里介绍一个新朋友,圆点运算符(.)。因为静态成员变量的访问方式是:类名.静态成员变量。你也可以通过new一个对象,从对象.静态成员来访问,但是这是一件合法却不合理的事情。
因为静态成员变量最大的特点就是不依赖于对象。从内存角度来理解,我们每创建一个类的引用,都会在虚拟机栈上开辟一个栈帧,这个引用指向堆上的一处空间,因为对象是放在堆上的。静态成员变量是存放在方法区的。
来看这个实例:
class Chinese {
public static int count;
}
public class Learning {
public static void main(String[] args) {
Chinese p = null;
System.out.println(p.count);
}
}
可见这里的p是不指向堆上空间的,却可以打印p.count。不过这样写只限于考题目,一般正规的写法是Chinese.count。也就是通过类名。
静态成员变量只有一份还有这种检验方法:
class Chinese {
public static int count;
}
public class Learning {
public static void main(String[] args) {
Chinese p1 = new Chinese();
p1.count++;
System.out.println(p1.count);
Chinese p2 = new Chinese();
p2.count++;
System.out.println(p2.count);
}
}
count初始值默认为0,可见p1、p2调用的同一个count,所以毫无疑问,count是不在堆上的。
2. 静态方法
静态方法也叫做类方法 。
class Chinese {
public static void func() {
System.out.println("调用静态方法");
}
}
public class Learning {
public static void main(String[] args) {
Chinese.func();
}
}
特别注意
静态方法中不可以使用普通的成员方法。因为普通成员方法,依靠于实例化对象,也就是在new之后,堆上才有他们。而静态方法是不依赖对象,这一点我一直在强调。
静态方法可以使用静态成员变量的,下面上代码:
class Chinese {
public static void func() {
count++;
System.out.println(count);
}
}
public class Learning {
public static void main(String[] args) {
Chinese.func();
}
}
静态的只能用自家的,而普通方法却可以使用静态的成员与方法。可以理解为静态的权限比较小。
四. final关键字
final带来的就是不可更改的效果,要改变final成员变量的任何操作都会报错。final不影响属性存放位置,存放在哪只看有没有static。
五. 重写类中的toString
class Person {
public String name;
public int age;
public String sex;
@Override //注解:确保重写方法名和被替代的的一样
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
}
public class Learning {
public static void main(String[] args) {
Person p = new Person();
System.out.println(p);
}
}
如果没有在类中重写toString方法,System.out.println§;会打印p的地址。如果类重新实现toString方法,会自动调用重写过的
六. 封装
1. private
用private来修饰属性或者方法就是封装。private/public是访问修饰符。
private修饰的属性,只可以在类内部使用。因为如果类的所有成员都能被其他类或者对象访问,会非常的不安全。代码的鲁棒性和可维护性会非常差。
封装也降低了类的使用者的使用成本,不必关注类当中的过多细节,类的实现者封装好属性与方法就可以。
2. set 和 get 方法
private修饰属性后,类外不可使用。所以用set
class Chinese {
private String name;
private String sex;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Chinese{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
'}';
}
}
public class Learning {
public static void main(String[] args) {
Chinese p = new Chinese();
p.setName("xiaoming");
p.setAge(10);
p.setSex("man");
System.out.println(p);
System.out.println(p.getName());
}
}
来看运行结果:
类的使用者只要使用set方法,就可以 设置 类属性的值;使用get方法来得到类属性的值。
这里用到了this方法,是为了安全性,后面会讲。
来看一个问题:
上面的代码不动,只改变setName中内容:
public void setName(String name) {
name = name;//原先为 this.name = name;
}
运行结果如下:
为什么name打印就变成null了呢?
原因是局部变量优先。name是setName()方法的形参。也就是说,方法中所写是形参自己给自己赋值,并没有作用到类中的属性。
正是这个原因,我推荐你有使用this的习惯。
七. 构造方法
1. 基本语法
构造方法是一种特殊方法, 使用关键字new实例化新对象时会被自动调用,用于初始化操作。
一言以蔽之:就是你一new,构造方法就被调用。
语法规则:
1. 方法名和类名相同
2. 无返回值
3. 是每个类都有的。如果你不创建,系统也会默认去创。
4. 若定义了构造方法,系统默认不执行
5. 支持重载
来看例子:
class Person{
Person() {
System.out.println("调用构造方法Person()!!");
}
Person(String name,int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Learning {
public static void main(String[] args) {
Person person = new Person();
Person person1 = new Person("ZTR",21);
System.out.println(person1);
}
}
运行结果:
2. this关键字
this代表当前对象的引用!!
在构造方法中可以使用this,构造方法运行结束,才在堆上开辟空间,创建对象。如果this代表对象,那就说明在this出生之前你就使用它。显然不合理。
而且由于this代表当前对象的引用,不可以在静态方法中使用。
(1)this();
调用当前构造方法
来看实例:
class Person{
String name;
int age;
Person() {
System.out.println("调用构造方法Person()!!");
}
Person(String name,int age) {
this();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Learning {
public static void main(String[] args) {
Person person1 = new Person("ZTR",21);
System.out.println(person1);
}
}
运行结果:
我们在调用含有两个参数的构造方法中,使用了没有参数的构造方法。
注意事项
1. 只可以在构造方法内使用
2. 必须写在第一行(方法内只可以使用一次)
3. this();中的参数不可以包含this.data
(2)this.data;
调用当前类的属性
this.name = name;
这就是实例。
(3)this.func();
调用当前类的方法
直接上代码:
class Chinese {
public void life() {
System.out.println("吃饭、睡觉、打豆豆");
}
Chinese() {
this.life();
}
}
public class Learning {
public static void main(String[] args) {
Chinese chinese = new Chinese();
}
}
运行结果:
八. 代码块
有普通代码块、实例代码块、静态代码块
1. 普通代码块
定义在方法中的代码块,没什么卵用,只作了解
2. 实例代码块
也叫做构造代码块。定义在 类 中的代码块
3. 静态代码块
由static修饰的,定义在 类 中的代码块
class Tset {
{
System.out.println("调用实例代码块");
}
static {
System.out.println("调用静态代码块");
}
Tset() {
System.out.println("调用构造方法");
}
}
public class Learning {
public static void main(String[] args) {
Tset test = new Tset();
}
}
运行结果
由上图可知,执行顺序为:
静态代码块 --> 实例代码块 --> 构造方法
注意事项
静态的代码块只会被执行一次,且最早被执行。
来看实例:
class Tset {
{
System.out.println("调用实例代码块");
}
static {
System.out.println("调用静态代码块");
}
Tset() {
System.out.println("调用构造方法");
}
}
public class Learning {
public static void main(String[] args) {
Tset test = new Tset();
System.out.println("=============");
Tset test2 = new Tset();
}
}
运行结果:
可见静态代码块只出现过一次
总结
类可以重复运用在程序中,有很好的拓展性,随时都可以用到。你会发现它的方便,并且爱上它。