前言
Java是一门典型的面向对象语言,即OOP,在面向对象的世界里,一切都是对象,所有的东西都是由对象来解决的,那么什么是面向对象呢?
其实面向对象就是一种编程思想,下面我来给大家介绍.
1 面向对象和面向过程
面向对象和面向过程都是一种编程思想.
什么是面向过程呢?看图:
就拿洗衣服举个例子,面向过程其实就是注重洗衣服的过程,比如:先拿个盆-> 放水->....晾衣服
把洗衣服这件事通过不同的过程来完成,但是如果我不想洗衣服,而是洗鞋子,那么很多过程对于洗鞋子就不会试用了.
也就是说,对于面向过程的语言,将来扩展和维护是十分麻烦的,而C语言就是一个典型的面向过程的语言.
面向对象图片如下:
整个过程其实是通过:人, 衣服,洗衣粉,洗衣机四个对象完成的,它并不关注我是怎么完成的,即不关注洗衣服的过程细节,但是它关注的是怎么通过这四个对象的交互完成这一过程的.
不过总而言之,不管是面向对象还是面向过程,存在即合理,都是有他们存在的价值的.都是解决问题的方法,并没有好坏之分,在不同场景使用不同的思想即可.
2 类的定义
在使用面向对象的思想解决问题时,我们面对的是一个个具体的实物,但是计算机并不知道,所以我要要使用一种规范,使用这种规范来定义出计算机能够读懂的东西.
这里就要引入类了,就如同上面的"人","洗衣机" 都是一种类.
上图就是定义一个类的具体规范,其中 class是关键字,后面可以跟着类名,而在类的内部可以定义类的属性和行为,下面来具体举个例子.
class关键字表示它是一个类,后面的"WashMachine" 其实就是类名,表示我创建了一个洗衣机类,
而在类内方法外的变量我们把它叫做成员变量,或者字段,属性.比如一个洗衣机的属性有它的品牌
,长,宽,高,颜色等等,其实就是为了描述这个类.
而写在类内的方法就是成员方法或者叫做行为,是为了规定这个类能够做些什么,如洗衣,脱衣,定时功能等等,后期想要拓展功能只需要在后面添加即可.
以上就是类的简单定义,但是对于类和类内部的字段和成员方法都是可以有修饰符修饰的,但是这个并不是现在的重点,后面会给大家注意讲解. 我们现在可以都先使用public,但是对与类,一个Java文件只能有一个被public修饰的类.
定义的类名一般使用大驼峰命名规范,其实就是类名的每个单词首字母都要大写,如(WashMechine),
一个Java文件最后只有一个类,
不过它们是一个软性的规定.
类的实例化
其实上面只是教大家定义一个类,但是一个类其实还是比较抽象的,我们并不知道这个类具体是什么样的.所以针对不同的场景,我们就可以给类实例化,而实例化后得到的其实就是一个个对象.
如:
public class Dog {
public String name;
public int age;
public void bark(){
System.out.println("汪汪汪~~~");
}
public void eat(){
System.out.println("小狗在吃饭");
}
}
class DogTest{
public static void main(String[] args) {
Dog d1 = new Dog();
d1.name = "旺财";
d1.age = 10;
System.out.println(d1.name + ", " + d1.age);
d1.bark();
d1.eat();
}
}
运行结果是:
这就是类的实例化和使用. 具体格式就是: 类名 对象名(类似于变量名,由你定) = new 类名();
针对于本题,其实就是 Dog dog = new Dog();
等号的左边其实就是定义一个变量,只不过它是一中比较特殊的类型,即我们自定义的类型.
等号的右边是一个new关键字的使用,不过这里面细节较多,后面细说,现在可以就按照这个定义.
在我上面的使用其实是跟我定义的属性和方法有关.
在我定义的时候 我定义了Dog类name 和 age属性,所以在使用时就可以给实例化对象赋上姓名和年龄,这里都是根据具体的需求定的,我们甚至还可以给它添加上颜色,品种等属性.
同样,方法也是的,我只定义了bark() 和 eat(),所以只能使用这两个方法.
下面来看看这个现象:
你可以发现我可以new两次,创建两个对象.
没错,其实类是可以创建多个对象,并且这两个对象是存储在不同的内存空间中,互不影影响
在看内存图之前,先补充一个细节:
在Java中局部变量如果没有初始化就使用的话就会报错,如下图:
你可以发现,它编译报错了.
但是成员变量是有初始化值的,换句话说,就是不初始化成员变量也是可以使用的.
默认初始化值:
整型:int:0 short:0 byte:0 long:0L ;
浮点型:float:0.0f double:0.0 ;
boolean类型的默认初始化值为false
char的默认初始化值为0或这'\u0000'
引用类型的默认初始化值为null
举个例子:
下面我来画一下它的内存图:
其实每次new一次,都会向内存申请一块独立的内存空间,不同的对象之间一般是独立的.
其实还可以这么理解类与对象之间的关系:类就相当于设计一个建筑图纸,你根据你的需求,在这里图纸中添加东西,但其实这个建筑并没有真实存在,在代码中就相当于类没有实例化,所以还不占用内存空间;但是只要根据图纸建造了一座建筑,就占用内存空间了,在代码中就相当于实例化类后申请了一块内存空间.
this引用
在一个类中,其实是有get和set方法的,那么什么事get和set方法呢?
set方法其实就是用来给成员变量赋值的,get方法可以获取成员方法的值,其实这两个方法是用处十分之大的,后面细说.
举个例子:
public class Cat {
public String name;
public int age;
public String getName() {
return name;
}
public void setName(String n) {
name = n;
}
public int getAge() {
return age;
}
public void setAge(int a) {
age = a;
}
}
class CatTest {
public static void main(String[] args) {
Cat c1 = new Cat();
c1.setAge(12);
c1.setName("小黄");
System.out.println(c1.getName());
System.out.println(c1.getAge());
}
}
运行结果如下:
所以是可以在类中定义这两个方法给成员变量赋值和获取的.
但是定义的set方法其实有一个问题,或者说是不好的地方,就是在参数列表局部变量的变量名不能做到见名知意.
那么我是否可以这样写:
public void setName(String name) {
name = name;
}
public void setAge(int age) {
age = age;
}
但是结果却是这样的:
这是因为变量赋值的时候是有局部优先的规则的,即方法中的两个变量其实都是局部变量本身,
而我的这个操作其实是将局部变量自己赋值给自己,压根没有成员变量事了.
那么我又想要见名知意又想要不会造成混淆,我该怎么办呢?
这里就要引入this引用,即this关键字.
public class Cat {
public String name;
public int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
可以这么理解:哪一个对象调用这个方法,那么这个this关键字就指向谁.
所以在这个方法中,在成员变量之前使用"this." 就表示这个变量其实是调用此方法的对象的成员变量,这样就十分完美了.
上述代码结果:
构造方法
在一个类中,其实是还有构造方法的,其实就是为了在创建对象的时候,来初始化对象.
构造方法的定义格式: 修饰符 类名(形参;列表){方法体;} 如:public Dog(){}
修饰符的事后面再说, 构造方法的方法名就是类名, 可以是有参数的,也可以是没有参数的,但是有一点需要注意就是没有返回值, 所以构造方法和普通的方法还是有一些区别的.
举个例子:
public Cat() {
}
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
在构造方法里我可以什么都不写,当然我也可以写一些代码,给我的成员变量初始化,等等.
那么在这里其实有一个疑惑,因为刚才已经写了好几个类了,我自己并没有写构造方法,为什么还是可以我创建的对象初始化了?
这是因为如果我们什么都不写的话,java就会给我们提供一个空参的构造方法,这个构造方法也是空实现的,这也就是为什么我们前面定义了没有构造方法的类还是可以初始化对象.
如何使用:
public class Cat {
public String name;
public int age;
public Cat() {
}
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
class CatTest {
public static void main(String[] args) {
Cat c1 = new Cat();
System.out.println(c1.getAge());
System.out.println(c1.getName());
System.out.println("----------------");
Cat c2 = new Cat("小白",11);
System.out.println(c2.getAge());
System.out.println(c2.getName());
}
}
以上就是它的使用,如果你仔细看的话,就会发现我们其实在一开始学习定义对象的时候就用到了构造方法,只不过那一个是Java提供的,而这次是我们自己写的.
因为空参构造是空实现,什么都没做,所以c1对应的成员变量的值其实是前面讲到的默认初始化值,而
如果通过有参构造创建对象,那么我传进去的局部变量其实会把默认的初始化值给覆盖掉.
结果如下:
那么如果我们自己提供了构造方法,Java会给我们提供吗?
想想也是不可能的,如果我们自己提供了构造方法,不管是什么构造,Java都不会再给我们提供了.
举个例子:
如果我的代码不提供空参构造,只提供有参数的构造,我再去使用空参构造创建对象,看看会不会报错
public class Cat {
public String name;
public int age;
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
我们自己并没有写空参构造方法,报错了,只能说明Java并没有给我们提供空参构造方法.
就地初始化
最后我们再讲一个小点,叫做就地初始化.
其实前面我们已经讲过了两种初始化方法:
第一种就是默认初始化.其实就是前面讲的成员变量的默认初始化值,
第二种就是通过构造方法初始化,我也不再赘述,
第三中就是就地初始化,其实就是我给成员变量定义的时候,可以顺便给它赋一个值.
如:
public class Cat {
public String name = "小黄";
public int age = 11;
public Cat() {
}
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
class CatTest {
public static void main(String[] args) {
Cat c = new Cat();
System.out.println(c.getName());//小黄
System.out.println(c.getAge());//11
}
}
谢谢
谢谢大家,我们下次再见!