1.类与对象的初步认识
C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。
JAVA是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。
面向过程注重的是过程,在整个过程中所涉及的行为,就是功能。面向对象注重的是对象,也就是参与过程所涉及到的主体。是通过逻辑将一个个功能实现连接起来
面向过程: 1.把冰箱打开 2. 把大象放入 3. 冰箱关起来
面向对象: 打开冰箱,储存,关闭都是对冰箱的操作,是冰箱的行为。冰箱就是一个对象,所以只要操作冰箱所具备的功能,都要定义在冰箱中。
【面向对象概念】
- 面向对象是思考问题的一种思考方式,是一种思想。比如:概念与实例 理论与实践 名和实等等。
- .类就是一类对象的统称。对象就是这一类具体化的一个实例。
- 面向对象的好处:将复杂的事情变简单了,只要面对一个对象就行。
【面向对象设计】
面向对象设计把握一个重要的经验:谁拥有数据,谁对外提供操作这些数据(私有)的方法!
(被动的一方是数据的拥有者,主动的一方是执行者)
开发时:找对象,建对象,用对象,并维护对象之间的关系。
简而言之
在Java当中,一切皆对象,比如你是一个对象,我也是一个对象,鼠标,键盘,手机等都是对象,那如何来描述我们所说的这些对象呢,就需要通过类来描述。面向对象就是用代码(类)来描述客观世界的事物的一种方式. 一个类主要包含一个事物的属性和行为。
这部分的内容相对来说可能有点抽象,但只要我们耐下心来去学,就会在失去耐心的同时,再得到一份痛苦。(开玩笑的)
2.类和类的实例化
面向对象就是用代码(类)来描述客观世界的事物的一种方式. 一个类主要包含一个事物的属性和行为。
基本语法:
class <class_name>{ field;//成员属性method;//成员方法
}
// 实例化对象
<class_name> <对象名> = new <class_name>();
class为定义类的关键字,ClassName为类的名字,{}中为类的主体。
类中的元素称为:成员属性。类中的函数称为:成员方法。
示例:
class Person {public int age;//(成员属性) 普通成员变量public static String name;//静态成员变量public String sex;public void eat() {//普通成员方法int a = 10;//局部变量System.out.println("吃饭!"); }public static void sleep() {//静态成员方法System.out.println("睡觉!"); }
}
注意事项:
- public是访问修饰限定符
- 类名(Person)的写法是大驼峰,即首字母大写
- 方法名(sleep和eat)的写法是小驼峰,即首字母小写,如果有两个单词,那么第二个单词的首字母要大写,举个例子:eatOne。
- 上面提到的方法相当于C语言里的函数,可以理解为对象的行为。
- 成员变量又分为普通成员变量和静态成员变量,成员方法也分为普通成员方法和静态成员方法,有static修饰的就是静态的。(此处作为了解,后面会详细讲解)
- 定义在方法里面的称为局部变量,比如在方法eat()中的’a’。要小心不能将局部变量和成员变量混淆了。
看到这里,我们已经轻松拿捏了这个所谓的类,的语法规则啦!
类的实例化
定义了一个类,就相当于在计算机中定义了一种新的类型,与int 和double类似,就可以自己创建一个这个类型的对象,此过程便称为实例化。
举个例子,比如现在我们要定义一个简单的学生类:
class Student{public String name;public int age;}
这样就很容易地定义了一个只有两个成员变量的学生类,理解了之后我们就可以在此基础上再添加一些方法了,比如要添加一个吃饭的方法,在这个方法里面我们先简单输出一句话:
class Student{public String name;public int age;}public void eat(){System.out.println("吃饭!");}
如何创建对象?
此时我们已经创建好了一个简单的学生类,那接下来就可以去创建对象了,我们可以使用new关键字,配合类名来创建一个对象。当然了,也可以创建多个对象。
class Student{public String name;public int age;}public void eat(){System.out.println("吃饭!");}
public class Test1 {public static void main(String[] args) {Student s1 = new Student();//创建了2个Student对象Student s2 = new Student();}
如何访问类中的成员变量和成员方法?
如果我们直接这样写的话就会出现这种情况:
public class Test1 {public static void main(String[] args) {Student s1 = new Student();System.out.println(s1);}
运行结果:
之所以会出现这种情况,是因为它们在内存中的存储情况是这样:
从图中我们不难看出,s1和s2中存放的都是地址,而且我们实例化出的对象占用实际的物理空间,存储类成员变量。
所以我们可以使用’ . '来访问对象中的属性和方法
比如对象名.属性 对象名.方法
class Student{public String name;public int age;}public void eat(){System.out.println("吃饭!");}
public class Test1 {public static void main(String[] args) {Student s1 = new Student();s1.String = "张三";s1.eat();}
3.类的成员
类的成员可以包含以下:字段、方法、代码块、内部类和接口等。此处我们重点介绍前三个:
3.1 字段/属性/成员变量
在类里面,方法外面定义的变量,我们称为"字段"或"属性"或"成员变量"(三种称呼都可以,一般不会严格区分)。
用于描述一个类中包含哪些数据。
class Person {//创建了一个Person类public String name; // 字段public int age;
}
class Test {public static void main(String[] args) {Person person = new Person();//创建了一个Person对象System.out.println(person.name);//输出nameSystem.out.println(person.age);//输出age}
}
// 执行结果
null
0
注意事项:
- 使用 . 访问对象的字段
- 这里所说的访问既包含读,也包含写
- 对于一个对象的字段,如果没有设置初始值,那么会被设置一个默认的初值。
默认值规则
对于各种数字类型, 默认值为 0.
对于 boolean 类型, 默认值为 false.
对于引用类型(String, Array, 以及自定制类), 默认值为 null
认识null
null在Java中为”空引用“,表示不引用任何对象,类似于C语言中的空指针。如果对null进行 . 操作就会引发异常。
class Person {public String name;public int age;
}
class Test {public static void main(String[] args) {Person person = new Person();System.out.println(person.name.length()); // 获取字符串长度}
}
// 执行结果
Exception in thread "main" java.lang.NullPointerExceptionat Test.main(Test.java:9)
字段就地初始化
很多时候我们不希望字段使用默认值,而是由我们自己去设置初值,可以这样写:
class Person {public String name = "张三";public int age = 18;
}
class Test {public static void main(String[] args) {Person person = new Person();System.out.println(person.name);System.out.println(person.age);}
}
// 执行结果
张三
18
但是这种初始化的方法我们不建议使用,除非有特殊的业务需求,比如任何一次对象的实例化之后,都期望这个对象叫张三,永远18岁,所以可以使用"方法"来进行初始化,首先让我们一起来学习什么叫做方法。
3.2方法(method)
方法主要用来描述一个对象的行为,比如吃饭,睡觉,展示等,举个例子:
class Person {public int age = 18;//属性/成员变量public String name = "张三";public void show() {//成员方法System.out.println("我叫" + name + ", 今年" + age + "岁");}//执行这条语句会输出对象的姓名和年龄
}
class Test {public static void main(String[] args) {Person person = new Person();person.show();//调用方法}
}
// 执行结果
我叫张三, 今年18岁
此处的show方法,表示Person这个对象具有一个"展示自我"的行为。这里的show方法和person实例是相关联的,如果创建了其他实例,那么show方法中输出的姓名和年龄就会发生变化。
Person person2 = new Person();//创建另一个对象
person2.name = "李四";//赋值
person2.age = 20;
person2.show()// 执行结果
我叫李四, 今年20岁
方法中还有一种特殊的方法称为构造方法(construction method),在实例化对象的时候会被自动调用,方法名字和类名相同,用于对象的初始化。
虽然我们前面已经能将属性就地初始化了,但是有些时候可能需要进行一些更复杂的初始化逻辑,那么就可以使用构造方法来进行初始化了。后面会详细介绍构造方法的语法。
3.3 static关键字
1. 修饰属性
Java静态属性和类相关,和具体的实例无关,换句话说,同一个类的不同实例共用同一个静态属性,举个例子:
class Student{public String name;public int age;public String classRoom = "110教室";
}
public static void main4(String[] args) {Student student1 = new Student();Student student2 = new Student();System.out.println(Student.classRoom);}
我们创建的对象他们指向的情况是这样的:
每个学生的姓名和年龄都不一样,但是他们都在同一个教室上课,所以"教室"只需要一份就可以了,那如果做到呢?我们只需要用static修饰classRoom就可以了,就像下面这样:
public static String classRoom = "110教室";
此时这个成员已经不属于对象了,换句话说,静态的成员变量不属于对象,而且静态的成员变量只有一份。
2. 修饰方法
如果在任何方法上应用static关键字,此方法称为静态方法。
- 静态方法属于类,而不属于对象
- 可以直接调用静态方法,而无需创建类的实例
- 静态方法可以访问静态数据成员,并可以更改静态数据成员的值。
class TestDemo{public int a;public static int count;//静态成员变量public static void change() {//静态成员方法count = 100;//a = 10; error 不可以访问非静态数据成员}
}
3. 如何访问静态的成员变量/方法?
我们可以通过对象访问,但是更推荐使用类名来访问,访问方式为类名 . 属性,如下面代码所示:
class TestDemo{public int a;public static int count;//静态成员变量public static void change() {//静态成员方法count = 100;//a = 10; error 不可以访问非静态数据成员}
}
public class Main{
public static void main(String[] args) {TestDemo.change();//无需创建实例对象,可以使用类名.调用System.out.println(TestDemo.count); }
}
//输出结果:100
总结:
1.static修饰的成员变量称为静态成员变量,其最大特性是不属于某个对象,属于类,所以在某些书里会把静态成员变量叫做类变量,静态成员方法叫做类方法。
2.静态成员变量/方法只有一份。
3.静态成员变量/方法可以通过对象访问,但一般更推荐使用类名访问。
4.this 和 super 两个关键字不能在静态上下文中使用(this 是当前实例的引用,super 是当前实例父类的引用,也是和当前实例相关)。
注意: main方法为static 方法。
4. 封装
什么叫封装?
在我们写代码的时候,经常会涉及两种角色:类的实现者和类的调用者。
封装的本质就是让类的调用者不必太多的了解类的实现者是如何实现类的,只要知道如何使用类就行了。这样就降低了类使用者的学习和使用成本,从而降低了复杂程度。
4.1 private实现封装
private / public 这两个关键字表示"访问权限控制"。
- 被 public 修饰的成员变量或者成员方法,可以直接被类的调用者使用。
- 被 private 修饰的成员变量或者成员方法,不能被类的调用者使用。
换句话说,类的使用者根本不需要知道,也不需要关注一个类有哪些 private 成员,从而让类调用者以更低的成本来使用类。
class Person {public String name = "张三";public int age = 18;}
class Test {public static void main(String[] args) {Person person = new Person();System.out.println("我叫" + person.name + ", 今年" + person.age + "岁");}
}
//执行结果:我叫张三,今年18岁
- 这样的代码导致类的使用者(main方法的代码)必须要了解 Person 类内部的实现,才能够使用这个类,学习成本较高。
- 一旦类的实现者修改了代码(例如把 name 改成 myName),那么类的使用者就需要大规模的修改自己的代码,维护成本较高。
同时如果类的实现者修改了字段的名字, 类的调用者不需要做出任何修改(类的调用者根本访问不到 name, age这样的字段)。
class Person { private String name = "张三"; private int age = 18; public void show() { System.out.println("我叫" + name + ", 今年" + age + "岁"); }
}
class Test { public static void main(String[] args) { Person person = new Person(); person.show(); }
}
//执行结果:我叫张三,今年18岁
- 此时字段已经使用 private 来修饰,类的调用者(main方法中)不能直接使用,而需要借助 show 方法,此时类的使用者就不必了解 Person 类的实现细节。
- 同时如果类的实现者修改了字段的名字,类的调用者不需要做出任何修改(类的调用者根本访问不到 name, age这样的字段)
那么问题来了,万一类的实现者修改了public方法show的名字,岂不是类的调用者仍然需要需要大量修改代码嘛?
这件事确实如此,但是一般很少会发生。一般类的设计都要求提供的public方法要比较稳定,不应该频繁发生大的改变。尤其是对于一些基础库中的类,更是如此,每次的接口变动都要仔细考虑兼容性问题。
注意事项:
- private不光能修饰字段,也能修饰方法
- 通常情况下,我们会把字段设为private属性,但是方法是否需要设置为public,就需要视具体情形而定。一般我们希望一个类只提供"必要的"public方法,而不是把所有的方法都一股脑设为public。
4.2 getter和setter方法
当我们使用private来修饰字段的时候,就无法直接使用这个字段了。
此时如果需要获取或者修改这个private属性,就需要使用getter / setter方法。
class Person { private String name;//实例成员变量private int age; public void setName(String name){ //name = name;//不能这样写this.name = name;//this引用,表示调用该方法的对象} public String getName(){ return name; } public void show(){ System.out.println("name: "+name+" age: "+age); }
}
public static void main(String[] args) { Person person = new Person(); person.setName("xixi"); String name = person.getName(); System.out.println(name); person.show();
}
//运行结果:xixi
// name : xixi age : 0
注意事项:
- getName 即为 getter 方法,表示获取这个成员的值。
- setName 即为 setter 方法,表示设置这个成员的值。
- 当set方法的形参名字和类中的成员属性的名字一样的时候,如果不使用this,相当于自己给自己赋值,this表示当前实例的引用。
- 不是所有的字段都一定要提供 setter / getter 方法,而是要根据实际情况决定提供哪种方法。
- 在IDEA中可以快速生成 setter / getter 方法,具体操作如下:
5.构造方法
5.1 基本语法
构造方法是一种特殊方法,使用关键字new实例化新对象时会被自动调用,用于完成初始化操作。
new执行过程
- 为对象分配内存空间
- 调用对象的构造方法
语法规则
- 1.方法名称必须与类名称相同
- 2.构造方法没有返回值类型声明
- 3.每一个类中一定至少存在一个构造方法(没有自己没有定义,则系统自动生成一个没有参数的构造方法)
注意事项:
- 如果类中没有提供任何的构造方法,那么编译器会默认生成一个不带有参数的构造方法
- 若类中定义了构造方法,编译器便不会再生成一个不带参数的构造方法
- 构造方法支持重载,规则和普通方法的重载一致。
class Person { private String name;//实例成员变量private int age; private String sex; //默认构造函数 构造对象 public Person() { this.name = "caocao"; this.age = 10; this.sex = "男"; } //带有3个参数的构造函数public Person(String name,int age,String sex) { this.name = name; this.age = age; this.sex = sex;} public void show(){ System.out.println("name: "+name+" age: "+age+" sex: "+sex); } }
public class Main{ public static void main(String[] args) { Person p1 = new Person();//调用不带参数的构造函数 如果程序没有提供会调用不带参数的构造函数p1.show(); Person p2 = new Person("zhangfei",80,"男");//调用带有3个参数的构造函数p2.show(); }
}
// 执行结果
/*name: caocao age: 10 sex: 男
name: zhangfei age: 80 sex: 男
5.2 this关键字
this表示当前对象引用(注意不是当前对象),可以借助this来访问对象的字段和方法。
public class Date {public int year;public int month;public int day;public void setDate(int y,int m,int d){//this.year = y;this.month = m;this.day = d;}
}public static void main(String[] args) {Date date = new Date();//new了第一个对象date.setDate(1999,1,1);date.print();Date date2 = new Date();//new了第二个对象date2.setDate(1989,11,11);date2.print();}
}
首先我们需要高清楚的一点是,上述的代码是如何通过方法给对象赋值的呢?
我们在上面提到,如果形参名称和我们的属性名称一样时,这样写就会出错:
而且,我们还需要考虑一个问题,这里的方法只有一个,那如何做到给两个对象赋值呢?是因为在setDate方法的参数中还有一个隐藏参数:
所以当形参名称和我们的属性名称相同的时候,我们就要这样写:
this的用法:
- this.成员变量
- this.成员方法
总结: - 谁调用这个方法,this就是谁
- this只能在成员方法中使用
- 在成员方法中,this只能引用当前对象,不能再引用其他对象
- 我们应当尽可能的多使用this,而不是只局限于上述的情况,多使用this不会有坏处
6. 认识代码块
字段的初始化方式有:
- 就地初始化
- 使用构造方法初始化
- 使用代码块初始化
前面两种方式已经学习过了,接下来我们介绍第三种方式,使用代码块初始化。
6.1 什么是代码块
使用{ }定义的一段代码
根据代码块定义的位置以及关键字,又可分为以下四种:
- 普通代码块
- 构造块
- 静态块
- 同步代码块(先搁置不谈)
6.2 普通代码块
普通代码块:定义在方法中的代码块。
public class Main{ public static void main(String[] args) { { //直接使用{}定义,普通方法块int x = 10 ; System.out.println("x1 = " +x); } int x = 100 ; System.out.println("x2 = " +x); }
}
// 执行结果
/*x1 = 10
x2 = 100
这种用法较少见。
6.3 构造代码块
构造块:定义在类中的代码块(不加修饰符),也叫:实例代码块。构造代码块一般用于初始化实例成员变量。
class Person{ private String name;//实例成员变量private int age; private String sex; public Person() { System.out.println("I am Person init()!"); } //实例代码块{ this.name = "bit"; this.age = 12; this.sex = "man"; System.out.println("I am instance init()!"); } public void show(){ System.out.println("name: "+name+" age: "+age+" sex: "+sex); } }
public class Main { public static void main(String[] args) { Person p1 = new Person(); p1.show(); }
}
/* 运行结果
I am instance init()!
I am Person init()!
name: bit age: 12 sex: man
注意事项:
实例代码块优先于构造方法执行。
6.4 静态代码块
使用static定义的代码块,一般用于初始化静态成员变量
class Person{private String name;//实例成员变量private int age; private String sex; private static int count = 0;//静态成员变量 由类共享数据 方法区public Person(){ System.out.println("I am Person init()!"); } //实例代码块{ this.name = "bit"; this.age = 12; this.sex = "man"; System.out.println("I am instance init()!"); } //静态代码块static { count = 10;//只能访问静态数据成员 System.out.println("I am static init()!"); } public void show(){ System.out.println("name: "+name+" age: "+age+" sex: "+sex); } }
public class Main { public static void main(String[] args) { Person p1 = new Person(); Person p2 = new Person();//静态代码块是否还会被执行?}
}
注意事项:
- 静态代码块不管生成多少个对象,其只会执行一次,而且是最优先执行的,
- 静态代码块执行完毕后,实例代码块(构造块)执行,再然后是构造方法执行。
7. 匿名对象
匿名只是表示没有名字的对象.
- 没有引用的对象称为匿名对象.
- 匿名对象只能在创建对象时使用.
- 如果一个对象只是用一次, 后面不需要用了, 可以考虑使用匿名对象
代码示例:
class Person { private String name; private int age; public Person(String name,int age) { this.age = age; this.name = name; } public void show() { System.out.println("name:"+name+" " + "age:"+age); }
}
public class Main { public static void main(String[] args) { new Person("caocao",19).show();//通过匿名对象调用方法}
}
/* 执行结果
name:caocao age:19
内容重点总结:
1 一个类可以产生无数的对象,类就是模板,对象就是具体的实例。
2.类中定义的属性,大概分为几类:类属性,对象属性。其中被static所修饰的数据属性称为类属性, static修饰的方法称为类方法,特点是不依赖于对象,我们只需要通过类名就可以调用其属性或者方法。
3.静态代码块优先实例代码块执行,实例代码块优先构造函数执行。
4.this关键字代表的是当前对象的引用。并不是当前对象。
学习可真是一件让人开心的事啊