面向对象程序设计概述
面向对象程序设计(object-oriented programming,OOP)是当今主流的程序设计范型,且java就是面向对象的。
对于一些规模较小的问题,将其分解为过程的开发方式比较理想,而面向对象更适合解决规模较大的问题。
面向对象程序设计是由对象组成的,每个对象包含对用户公开的特点功能部分和隐藏的实现部分,程序中的很多对象来自标准库。
类
类(class)在面向对象编程中是一种面向对象计算机编程语言的构造,是创建对象的模板或者蓝图,描述了所创建的对象共同的特性和方法。由类构造(construct) 对象的过程称为创建类的实例化(instance)
封装(encapsulation,有时候称为数据隐藏)是处理对象的一个重要概念。从形式上看,封装就是将数据和行为组合在一个包中,并对对象的使用者隐藏具体的实现方式。对象中的数据成为实例字段(instance field),操作数据的过程称为方法(method)。作为一个类的实例,特定对象都有一组特定的实例字段值。这些值的集合就是这个对象的当前状态(state)。无论何时,只要在对象上调用一个方法,它的状态就有可能发生改变
对象
对象的三个主要特性
对象的行为(behavior)——可以对对象完成哪些操作,或者可以对对象应用哪些方法?
对象的状态(state)——当调用那些方法时,对象会如何响应?
对象的标识(identity)——如何区分具有相同行为与状态的不同对象?
同一个类的所有对象实例,由于支持相同的行为而具有家族式的相似性。对象的行为是用可调用的方法来定义的。
此外,每个对象都保存着描述当前状况的信息。这就是对象的状态。对象的状态可能会随着时间的而发生改变,但这种改变不是自发的。对象状态的改变必须通过调用方法实现(如果不经过方法调用就可以改变对象状态,只能说明破坏了封装性)
类之间的关系
在类中,最常见的关系有
依赖(“uses-a”)
依赖(dependence),即“uses-a”关系,是一种最明显的,最常见的关系。但是应该尽可能的将相互依赖的类减至最少。既减少类之间的耦合
聚合(“has-a”)
聚合(aggregation),即“has-a”关系,很容易理解,类A的对象包含类B的对象
继承(“is-a”)
继承(inheritance),即“is-a”关系,表示一个更特殊的类与一个更一般的类之间的关系
用代码认识类和对象
1:
类
Person 为类名(一般为大驼峰,也就是首字母要大写)
name,sex,age 是 Person 这个类的属性,也叫做字段,常见的叫做成员变量
learn 是 Person 这个类的方法,也叫做成员方法
class Person{
public String name;
public String sex;
public int age;
public void learn(){
}
}
2:
实例化
class Person{
public String name;
public String sex;
public int age;
}
public class Code {
public static void main(String[] args) {
Person person = new Person();
// 类型 变量(引用) 对象
}
}
person 是一个变量,这个变量在栈区里面存储的是地址,这个地址在堆区里面开辟了一块空间,用于存储Person这个对象,Person这个对象包含了它本身的属性(name;sex;age),也叫做person引用了Person这个对象
![](https://i-blog.csdnimg.cn/blog_migrate/0bd2b5c239774147bfb517579305b695.png)
3:
如果没有对成员变量初始化则默认为以下这些
整形(int,short,long,byte)默认为0
字符串(String)默认为null
浮点类型(float,double)默认为0.0
布尔类型(boolean)默认为false
public class Code {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person.name); // null
System.out.println(person.sex); // null
System.out.println(person.age); // 0
}
}
通过 ”.“来给其赋值,让其实例化
person.name = "jack";
person.sex = "man";
person.age = 18;
在类中实现一个show()方法,在主函数中直接通过 person(变量)引用+”.“+方法名 打印
class Person{
public String name;
public String sex;
public int age;
public void show(){
System.out.println("姓名:"+name+" 性别:"+sex+" 年龄:"+age);
}
}
public class Code {
public static void main(String[] args) {
Person person = new Person();
person.name = "jack";
person.sex = "man";
person.age = 18;
person.show();
}
}
一个类可以实例化多个对象
person和person1都引用了Person这个对象,但是在堆区开辟了不同的空间用于储存Person这个对象,他们之间相互没有影响
class Person{
public String name;
public String sex;
public int age;
}
public class Code {
public static void main(String[] args) {
Person person = new Person();
Person person1 = new Person();
}
![](https://i-blog.csdnimg.cn/blog_migrate/7fce973f5e39fcfdf633cb7fd7d2e017.png)
只要new一个Person,那么每一个Person都有它的成员变量
class Person{
public String name;
public String sex;
public int age;
public void show(){
System.out.println("姓名:"+name+" 性别:"+sex+" 年龄:"+age);
}
}
public class Code {
public static void main(String[] args) {
Person person = new Person();
person.name = "jack";
person.sex = "man";
person.age = 18;
Person person1 = new Person();
person1.name = "jeff";
person1.sex = "man";
person1.age = 22;
person.show();
person1.show();
}
![](https://i-blog.csdnimg.cn/blog_migrate/1db0c4d530b50fc95219c5f43cdc001f.png)
关于静态成员变量的一些语法知识
1:
如果将一个字段定义为static,那么每个类只有一个这样的字段,也就说被static修饰的字段在所属的类中是唯一的
![](https://i-blog.csdnimg.cn/blog_migrate/dcfc002b9c8cad4452da3c51137b7855.png)
![](https://i-blog.csdnimg.cn/blog_migrate/28072d850cf26fd066bba07480d6d3bd.png)
静态成员变量是在方法区,所以它不会和普通成员变量一样在堆区开辟不同的空间
静态成员变量也不适合通过对象访问,直接通过类名访问即可
public static void main(String[] args) {
Person.count1++;
// 类名 静态成员变量
System.out.println(Person.count1);
}
![](https://i-blog.csdnimg.cn/blog_migrate/c6e16c4702f737f9a9da372666ed1f19.png)
2:
在普通方法内部不能定义静态变量
因为普通方法内部的变量是属于这个方法的
但是被static修饰的变量是属于类的,是可以直接通过类名访问的
![](https://i-blog.csdnimg.cn/blog_migrate/77643cee46a9c22dc64bddfc1c9a786e.png)
3:
在静态方法内部也不能定义静态变量
![](https://i-blog.csdnimg.cn/blog_migrate/3ced223dc638a7d28b529b7e621111ee.png)
4:
在普通方法内部可以调用静态方法,且按照代码的顺序来调用
![](https://i-blog.csdnimg.cn/blog_migrate/b34107e0868f64a94b15b960a820762d.png)
5:
相反,在静态方法内部不能调用普通方法
静态方法不依赖于对象,通过类名可以直接调用
普通方法依赖于对象,必须要new对象,所以冲突了
![](https://i-blog.csdnimg.cn/blog_migrate/e8d2ac73cb6f0574667487cd7d1ba11e.png)
6:
特殊情况:在静态方法内部new一个对象就可以调用普通方法
这种情况很少见,可能会产生bug,不建议使用
![](https://i-blog.csdnimg.cn/blog_migrate/923d2fdfc04385f73c40886bb8a7c7c5.png)
static变量只能在类里面,方法的外面定义
引用
引用的一些语法知识
1
null是引用的初值
public static void main(String[] args) {
Person person = null;
}
person这个引用不指向任何对象
2
public static void main(String[] args) {
Person person = new Person();
Person person2 = person;
}
person2这个引用指向了person这个引用所指向的对象
3
public static void main(String[] args) {
Person person = new Person();
person = new Person();
person = new Person();
person = new Person();
person = new Person();
person = new Person();
}
只需要看最后一次所指向的对象
一个引用不可以同时指向多个对象
4
引用不一定都是在栈上的
![](https://i-blog.csdnimg.cn/blog_migrate/519d1c1ccba7045ec90ee406d355fa2f.png)
浅谈封装
概念&关于封装的一些语法知识
private/ public 这两个关键字表示 “访问权限控制”
被 public 修饰的成员变量或者成员方法, 可以直接被类的调用者使用.
被 private 修饰的成员变量或者成员方法, 不能被类的调用者使用.
1:
当需要修改普通成员变量的名字时,会导致需要修改大量代码
![](https://i-blog.csdnimg.cn/blog_migrate/bc0f735ae00ee60cf08247511611b316.png)
2:
所以需要保护这个普通成员变量,在它前面加上private,它的属性就变成受保护的了
![](https://i-blog.csdnimg.cn/blog_migrate/d661ce956da803da31143c21d0142c1b.png)
当一个属性或者方法被private修饰过后,那么这个属性或者方法就被封装了
那么就只能在当前的类当中去使用它,所以在类外就不能使用它
3:
![](https://i-blog.csdnimg.cn/blog_migrate/8c66418ef7ab1c2828e2ce02ef6d111d.png)
4:
被private修饰的属性,就会给其提供公开的get和set接口
class Person{
private String name;
private 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;
}
}
public class Code {
public static void main(String[] args) {
Person person = new Person();
person.setName("jack");
person.setAge(20);
System.out.println(person.getName());
System.out.println(person.getAge());
}
}
这么做的好处是类的调用者不必关心类内部是怎么实现的,只需要用到set和get接口来访问,接口是不可改变的
5:
当set方法的形参名字和类中的成员属性的名字一样的时候,如果不使用this, 相当于自赋值.
![](https://i-blog.csdnimg.cn/blog_migrate/df4c40c0e27134f9ff61598a80d36e3c.png)
this代表当前对象的引用,所以保持良好的代码习惯,加上this是最优解,不过一般编译器都会自动生成
浅谈构造方法
概念&关于构造方法的一些语法知识
1:
构造方法的方法名和类名是相同的,且构造方法没有返回值
![](https://i-blog.csdnimg.cn/blog_migrate/0439b0012266feef6d61df7b562b9ad9.png)
2:
一个类至少有一个构造方法,如果没有写,那么编译器会帮助生成一个不带参数的构造方法
class Person{
public Person(){
System.out.println("不带参数的构造方法");
}
}
public class Code {
public static void main(String[] args) {
Person person = new Person();
// ↑ 调用不带参数的构造方法
}
}
3:
如果当前类有其他构造方法,那么编译器就不会帮助生成不带参数的构造方法
![](https://i-blog.csdnimg.cn/blog_migrate/ea10f2861415b85adc5ca319ab55ae79.png)
4:
构造方法如果被private修饰,那么只能在它所在的类内调用,类外是不能调用的
![](https://i-blog.csdnimg.cn/blog_migrate/69f6a6141279320078558e0fb17289d3.png)
5:
构造方法之间可以构成重载
重载:方法名相同,参数列表不同,返回值不做要求
class Person{
private String name;
private int age;
public Person(){
System.out.println("不带参数的构造方法");
}
public Person(String name){
this.name = name;
System.out.println("带一个String类型参数的构造方法");
}
public Person(String name,int age){
this.name = name;
this.age = age;
System.out.println("带一个 String 和一个 int 类型参数的构造方法");
}
}
public class Code {
public static void main(String[] args) {
Person person = new Person();
Person person2 = new Person("Tom");
Person person3 = new Person("jack",20);
}
}
浅谈 this 关键字
this关键字的语法
1:
调用当前对象的属性
class Person{
private String name;
public Person(String name){
this.name = name;
}
}
2:
调用当前对象的方法
class Person{
private String name;
public void func1(){
}
public void func(){
this.func1();
System.out.println("The func of Person");
}
}
3:
调用当前对象的其他构造方法
![](https://i-blog.csdnimg.cn/blog_migrate/2e6ff2830a7688df1b0503df3aab0b99.png)
![](https://i-blog.csdnimg.cn/blog_migrate/434258ea96296cf5d1b086531b50af25.png)
4:
this调用当前对象的构造方法,只能放在方法的第一行
![](https://i-blog.csdnimg.cn/blog_migrate/7925040dc7cae68d117a850ba6297f55.png)
![](https://i-blog.csdnimg.cn/blog_migrate/653e0f21fb925e49b4415f78ff62f17d.png)
5:
不能在成员方法内部使用this调用构造方法
![](https://i-blog.csdnimg.cn/blog_migrate/137b7f39ac6cda6c17ffcd3c81f973e9.png)
代码块的语法知识
实例代码块&静态代码块
1:
静态代码块在类加载的时候就被调用了,无论在类中的什么位置,都是优先于实例代码块
class Person{
private String name;
private int age;
// 实例代码块
{
System.out.println("实例代码块");
}
// 静态代码块
static {
System.out.println("静态代码块");
}
public Person(){
System.out.println("不带参数的构造方法");
}
}
public class Code {
public static void main(String[] args) {
Person person = new Person();
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/83bcf9a30929886be64cb2721d5da918.png)
2:
静态代码块只会被执行一次
class Person{
private String name;
private int age;
// 实例代码块
{
System.out.println("实例代码块");
}
// 静态代码块
static {
System.out.println("静态代码块");
}
public Person(){
System.out.println("不带参数的构造方法");
}
}
public class Code {
public static void main(String[] args) {
Person person = new Person();
System.out.println("------------------------");
Person person1 = new Person();
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/1d04546ab88bf296a4234d8b4b556ae0.png)
3:
静态代码块不用实例化对象也可以被执行
class Person{
public static int count;
{
System.out.println("实例代码块");
}
static {
System.out.println("静态代码块");
}
}
public class Code {
public static void main(String[] args) {
System.out.println(Person.count);
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/fc22a091a5d1921faa1d8b166b3659ac.png)
4:
静态代码块可以给静态成员变量赋值
class Person{
static {
count = 99;
System.out.println("静态代码块");
}
public static int count;
}
public class Code {
public static void main(String[] args) {
System.out.println(Person.count);
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/50250dd5f4bfbb4e55c077470ff588be.png)
5:
如果都是静态的,那么执行的顺序和定义的顺序有关系
![](https://i-blog.csdnimg.cn/blog_migrate/1c3c32f1ec307252afe9a866399311bf.png)
6:
如果静态成员变量没有被赋值,那么按照静态代码块的结果
![](https://i-blog.csdnimg.cn/blog_migrate/f4bad5689ae749aa23bdae879fd545f4.png)
小结:
静态代码块不管生成多少个对象,其只会执行一次,且是最先执行的
静态代码块执行完毕后, 实例代码块执行,再然后是构造函数执行
浅谈匿名对象
匿名表示没有名字的对象,没有引用的对象也称为匿名对象
匿名对象只能在创建对象时使用
![](https://i-blog.csdnimg.cn/blog_migrate/4bae823db29ad3e10ad5c72ed8c5879f.png)
总结
一个类可以产生无数的对象,类就是模板,对象就是具体的实例
类中定义的属性,大概分为几类:类属性,对象属性。其中被static所修饰的数据属性称为类属static修饰的
方法称为类方法,特点是不依赖于对象,我们只需要通过类名就可以调用其属性或者方法
静态代码块优先实例代码块执行,实例代码块优先构造函数执行
this关键字代表的是当前对象的引用,并不是当前对象