《Java面向对象》
三条主线
- Java类及类的成员 : 属性、方法、构造器、代码块、内部类
- 面向对象的三大特征:封装性、继承性、多态性、
- 其他关键字:private、缺省、protected、public、static、final、package、extends、this、super、interface、implements、abstract
1. Java类及类的成员
-
属性: 这个词只有类中有, 在其他地方都是叫变量,属性其实也是变量的一种,只不过在类中不叫变量, 也就是对象的属性
-
方法:方法和其它编程语言的函数很像,只是叫法不同而已,方法,就是对应类中成员的方法
// 声明一个类用要 关键字class class Person { int age; // 属性 String name; // 属性 // 在类的里面写的就叫属性,属性就是长这样 public void eat() { // 方法 int a; // 这个就不叫属性了, 这里称为局部变量 System.out.println("吃饭"); // 表示对象能干这个事, } } // 测试 public class Main { public static void main(String[] args) { Person p = new Person(); // 造了一个对象 // Person可以理解为,一种类型,就像基本数据类型一样, 而p就是这样类型的类型名 // 然后这里就是造了一个对象p // 如果要调用属性的话 int a = p.age; // 这里就是调用了对象的属性, 就是用 "对象.属性" // 调用方法 p.eat(); // 调用方法 "对象.方法" } }
这里就简单介绍了下属性和方法。
上面我们可以看到在造对象时 用了
new Person()
,new
这时一个关键字,可以理解为就是在内存中开辟一个空间了关键字,但是后面要讲的Person()
就很重要了, 形如这样的都是叫构造器,下面细细讲下 构造器。 -
构造器:构造器说的简单一点就是创建对象用的,当然也不只是这一个功能,只不过这时最常用的,造对象就一定要用构造器,没有构造器就创建不了对象
class Person { int age; // 属性 String name; // 属性 // 构造器 // 如果向上面的类一样虽然没有写构造器 但是调用了Object类中空参构造器, 也就是说一个类中至少有一个构造器 // Object类是除它自己所有类的父类 public Person() { // 这是一个空参的构造器, 构造器和类名的时一样的 } // 这里就是带参构造器, 也就是说在造对象时可以初始化一些对象的信息 // 比如说这里就能初始化 对象的年龄和姓名 public Person(int a, String n) { age = a; name = n; } // 方法 public void eat { System.out.println("吃饭"); } } public class main { public static void main(String[] args) { Person p = new Person(); // 这里是造了一个空参的对象, 也就是说没有对对像经行一些初始化 int a1 = p.age; p.eat(); ✨// 发在这里我们应该是能发现, 构造器都是和类名是一样的, 这是一个重要的点 Person p1 = new Person(20, "pan"); // 对对象经行了初始化了年龄和姓名 // 要注意的是这里是两个对象, 每new一次就是一个新的对象 int b = p1.age; p1.eat(); // 如果在内存上解释的话, 这两个对象指向了不同的地址 // new出来的是在堆空间中, 而对象是在栈中 因为new了两个次所以分别指向了不同的地址 } }
-
重载:什么是重载? 在同一个类中同一个方法名, 但是参数列表不同,这个就叫重载。
上面两个构造器就形成了重载,只要满足同一个类同方法名, 不同参数列表就是重载, 属性是不存在重载的说法的
✨同一个类同一方法名,不同参数列表;
和返回类型是没有关系, 和权限也没有关系;
不同参数表示的是,要么就是参数的类型不同, 要么就是参数的个数不同;
如果参数个数相同, 但只是参数名不同, 那就不构成重载。
class Dog { int age; String name; public Dog() { } // 这里的两个构造器就是重载 因为满足 同一个类同一方法名, 不同参数列表 public Dog(int a, String n) { age = a; name = n; } // 这里两个方法也是构成了重载 public void eat() { System.out.println("吃饭"); } public void eat(String n) { System.out.println(n + "吃好吃的"); } public int eat(int a) { // 这里也是构成了重载,也是满足条件,和返回类型是没有关系的 System.out.println("11111"); return 0; } /* public void eat(int b) { 这里就不是重载了, 因为这里的参数列表相同了, 因为只是变了一个参数名而已, 类型还是一样的 System.out.println("2222"); } */ public void eat(int a, String n) { // 这个也是重载 } /* 这个就不是重载了这里只是改了权限, 和权限是没有关系的 private void eat(int a, String n) { } */ }
-
return关键字的使用
-
- 结束方法
-
- 返回值
如果接触过其他语言的人就不陌生,在其它语言可能不是叫做方法, 而是叫做函数, 像上面方法eat,有返回类型void,int的
void
这就表示是空, 也就是没有返回值, 可以理解为,可以不用return关键字, 当然也是可以用的, 那么这时就不是表示为返回值的意思了, 而是结束这个方法的意思了。int
这个就是要有返回值了,返回值为int类型的值, 那么什么是返回值, 就是你再调用时,会有一个数返回到你调用的那个位置, 你就要一个变量来承接它,就相当于这个返回值对这个变量经行了赋值,那么你就要用return关键字了, 而且后面得带值, 比如 return 1;表示的就是结束这个方法再返回1这个数。 -
-
利用类的这种类型来声明一个数组
class arr { int age; String name; public void eat() { System.out.printf("吃饭"); } } public class Main { public static void main(String[] args) { // 表名声明了空间为10大小的数组, 类型是一种类 // 这种叫做对象数组 arr[] a = new arr[10]; // 这里就只是简单声明了一个数组, 并没有创建对象 // 如果你要创建对象,就要这样 a[0] = new arr(); // 如果你要用到你创建的数组的所有的空间那么你可以这样创建对象 for (int i = 0; i < 10; i ++) a[i] = new arr(); // 如果你用不到所有的空间,那么你就可以边创对像边使用, 这样可以减少空间和时间上消耗 // 注意: 这里每一个数组都是对象, 都是有相应属性和方法的 都是能通过 "a[X].属性" 或 "a[X].方法" 进行调用 a[0].age = 10; // 这里就是给0位置上属性进行赋值 a[0].eat(); } }
-
方法的形参的传递机制: 值传递机制
-
如果变量是基本数据类型,此时赋值的时变量所保存的数值值,也就是是这个变量所存的真实的值
-
如果变量是引用数据类型,此时赋值的是变量所保存的数据的地址值,引用数据类型就是对象变量
-
==
这个等号, 如果是判断两个是变量是基本数据类型,则判断的是 这两个变量的真实值是不是相等,如果是两个变量是引用数据类型的话, 那就是判断这两个变量所在的地址是不是相等,通俗的讲, 就是这两个变量是不是指向同一个地址 -
总的来讲,
==
对于基本数据类型比值,对于引用数据类型看地址
-
2. 面向对象三大特征
-
封装性:隐藏对象内部的复杂性,只对外公开简单的接口。 通俗的讲:把该隐藏的隐藏起来,该暴露的暴露出来。这个就是封装性的思想
-
封装性体现在, 四种权限修饰符上,
private
default(缺省)
protected
public
- private: 私有的, 就是只能自己的类中使用
- default : 默认的, 是不写出来的,权限比private会稍微大一点, 能在同一个类中使用, 也能在同一个包下不同类中使用
- protected: 权限又会大一点, 能在同一个类中使用,也能在同一个包不同类中是用,也能在不同包中使用
- public: 权限最大,只要在一个工程里都能调用
-
正是上面这四种权限修饰符完美的体现了封装性的特点
class Arr { private int age; // 用private权限修饰符修饰,表示只能在这个类中使用, 就体现了封装性的特点 // 就是不想让其他类直接调用这个属性, 在其他类中就使用不了 private String name; // 这个也是一样,不想让其他类直接使用这个属性 int id; // 这个还是默认的 public Arr() { // 空参构造器, 一旦定义了非空参的构造器那就不存在空参构造器了, 也就是说一般都会定义一个空参的构造器 } public Arr(int age, String name, int id) { // 创建对象时,初始化了一些信息 这里有一个this关键字 this.age = age; this.name = name; this.id = id; } // this关键字, 表示当前对象的,当前正在创建对象的 // 当前对象的------就是new一个对象时,这个new出来的对象的,属性,方法,构造器等 //当前正在创建对象的-------这里也是new一个对象时,但是这里时创建匿名对象时的,属性,方法,构造器等 // 那么是匿名对象-------直接用new关键字的对象,也就是没有把这个对象赋给一个对象变量 public void setAge(int age) { // 这里也体现了封装性, 虽然我们不能直接调用age属性, 但是我们能通过这方法来间接设置 this.age = age; } public int getAge() { // 这里通过方法间接调用, 也就是不能直接去修改属性了 只能通过调用相应的方法间接调用属性, // 这就很好的体现了封装性的思想:该隐藏的隐藏,该暴露的暴露 return this.age; } public void setName(String name) { // 这里也是通过方法间接调用,使用这个属性,因为有封装性,就不能直接调用属性,所有要调用方法来间接调用 this.name = name; } public String getName() { // 这里也是一样的 return this.name; } }
-
this关键字
-
上面有关键字
this
,这个关键字,可以理解为 当前对象的或当前正在创建对象的 虽然之前也有很多写了很多类,但是没有写this
这是因为参数名和属性名不同,还有就是虽然没有写,只是省略了,其实还是有this关键字的, 但是这个类参数名和属性名相同了,这时就要分出哪个是属性,哪个是参数,就要用this
关键字,不然就会编译报错, 回到上面。 -
this
关键字用在构造器上, 这个就有点麻烦了。2.1 最多只有有一个this关键字;
2.2 如果是用调用无参构造器时,形如
this()
;2.3 因为最多只有一个,也就是说只能放在构造器的首行;
2.4 调用有参数的构造器时,形如
this(a, b, c, ...)
;2.5 如果有n个构造器,就有n-1个this关键字,还有一个是
super
关键字,super
关键字之后再谈。
-
-
static关键字
表示静态的意思,所谓静态的意思就是 就以属性为例,如果定义了一个属性为静态的就说明这个属性是这个类公共的属性了
如果创建了两个类的话, 那么这个属性是公共的, 也就是说 只要在一个类中修改了 这个属性, 那么在另一个类中, 这个属性值 也被修改了,之后调用的就是修改之后的属性值了。
举个最基本的例子来说明就是 每个一个中国人 省份证号码, 电话号码, 等等都是不同的, 但是所有的人都国籍是一样的 都是中国, 所以国籍就是静态的属性,如果国家改名字了, 那么大家的国籍也就跟着改了。
- 标记的位置:属性、方法、代码块、内部类;
- 随着类的加载而加载,所以称静态的属性和方法为类属性,类方法,一般不叫类方法而叫静态属性。
- 非静态的随着对象的创建而加载
- 从生命周期解释,静态的比非静态先加载。
class Person { private int age; // 体现了封装性, 只要使用了权限修饰符就是体现了封装性的特点 private String naem; int id; public static int cnt; // 这里就是把属性设置为静态的了, 也就是说这个一个类属性 // 也就是说这个属性比上面的属性先加载,静态属性是随着类的加载而加载, 那么就可以通过 "类.属性",去调用这个属性 // 在内存中 静态属性是在方法区的静态域中, 还有就是静态属性只会加载一次, 也就是说不管你创建了几个对象静态属性只会被创建一次 // 如果是非静态属性,也就是对象属性, 这个是每new一次对象就会被加载一次,且每个对象属性是不同的,静态属性都是相同的 public Person() { // 空惨构造器 } public Person(int age, String name) { this.age = age; this.name = name; } public Person(int age, String name, int id) { this(age, name); // 这里就是利用this关键字调用构造器,上面也讲了,怎么使用的,一个构造器最多只有一个this关键字 // 且只能放在首行 this.id = id; } public static void eat() { // 这里是一个静态方法,这个也是随着类的加载而加载,且只加载一次。基本和静态属性是一样的 System.out.printf("吃饭"); // 也是能通过 "类.方法名" 调用 } public void sleep() { // 非静态方法, 也就只能通过 "对象.方法名" 调用, System.out.printf("睡觉"); } }
-
继承性:字面意思,就是当前一个类继承了另一个类全部的属性和方法
- 减少了代码的冗余
- 便于功能的扩展
- 为之后的多态性的使用,提供了前提
- 关键字
extends
class Person { private int age; private String name; int id; public Person() { } public Person(int age, int id, String name) { this.age = age; this.nane = name; this.id = id; } public void eat() { System.out.printf("吃饭"); } } class Student extends Person { // 这里就表示继承了,当前类继承了Person类 private int xuehao; int min = 0; public Student() { } public Student(int age, int id, String name, int xuehao) { super(age, id, name); // 这里是一个关键字,this关键字可以理解为 当前对象的,当前正在创建的对象的 // 而super关键字 则表示,父类的,只要是父类的就是, 不管是直接父类或间接父类, 这里就是里用super关键字调用父类的构造器。 this.xuehao = xuehao; } public void eat1() { System.out.printf("吃好吃的"); } @Override // 这里是一个重写 public void eat() { System.out.printf("学生吃有营养的食物"); } } public class Main { public static void main(String args) { Student s = new Student(); // 这创建了一个学生对象,学生也是人有姓名和年龄,所以就继承了父类的属性 // 也就是说可以通过 "s.父类属性或方法" s.eat(); // 这个是通过继承来的 s.eat1(); // 这个是它自己所有的 // 当然也是能调用属性的 int a = s.id; // 通过继承得来得 int b = s.min; // 自己所有得 // 如果调用父类的私有属性 就会报错 // String nm = s.name; 这里体现的封装性, 是不能直接调用, 但是不能说没有继承到, 实际上子类是继承到了的 // 只不过是由于封装性的特点,而不能直接调用了,只能相应的方法间接调用, 私有的方法也是一样的 } }
-
重写:父类的方法的功能可能对子类就不太适用了, 这时子类就要对父类的方法进行重写,也就是说一般就只是重新对方法体进行重写
- 属性是没有重写这一说法的
- 子类重写的方法权限修饰不小于父类被重写的方法
- 返回类型必须一致如果父类是基本数据类型子类也一定是,父类是void类型,子类也一定是,除了引用数据类型,返回类型可以是父类的子类型
- 方法名要一致
- 参数列表要一致
-
重载和重写