面向对象思想的几大特征:继承、封装、多态。面向对象语言不只有Java,还有C 、C++等。
一、封装 1.概念(1) 从语法层面上:字段和方法都被private修饰,此时就是把这个字段和方法进行封装;
(2) 本质:让类的调用者不必太多的了解类的实现者是如何实现类的, 只要知道如何使用类就好了;
(3) 意义:安全;降低了类的使用成本。
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("caocao");
String name = person.getName();
System.out.println(name);
person.show();
}
(1) getName/setName 即为 getter /setter方法, 表示获取这个成员的值;
(2) 当set方法的形参名字和类中的成员属性的名字一样的时候,如果不使用this, 相当于自赋值. this 表示当前实例 的引用。
3. this关键字关键字this表示当前对象的引用,作用如下:
(1) 调用属性,也就是调用本类中的成员变量;
(2) 调用方法,就是调用本类中的其他方法;
(3) 构造函数,静态构造方法不能调用类的属性;不能出现第二个this.();且调用时只能放在第一行;
4.构造方法使用关键字new实例化新对象时会被自动调用;用于完成初始化操作;
(1)实例化对象
- 为对象分配内存;
- 调佣的合适的构造方法(构造方法不止一个);
(2)注意事项
- 当没写构造方法时,编译器会自动生成一个不带参数的构造方法;
使用 {} 定义的一段代码,根据代码块定义的位置以及关键字,又可分为以下四种:
(1)本地代码块:方法内部定义的;
-
示例:
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); } }
(2) 实例代码块/构造代码块:在方法外部,类的里边;一般用于初始化实例成员变量;
-
示例:
class Person{ private String name;//实例成员变量 private int age; private String sex; //实例代码块 { this.name = "bit"; this.age = 12; this.sex = "man"; System.out.println("I am instance init()!"); } } public class Main { public static void main(String[] args) { Person p1 = new Person(); p1.show(); } }
(3) 静态代码块:被static修饰的代码块;一般用于初始化静态成员属性;
-
示例:
//静态代码块 static { count = 10;//只能访问静态数据成员 System.out.println("I am static init()!"); }
(4) 同步代码块;
(5) 总结:静态代码块其只会执行一次,且是最先执行;静态代码块执行完毕后, 实例代码块(构造块)执行,再然后是构造函数执行。
6.匿名对象(1)概念
- 没有引用的对象称为匿名对象;
- 只能在创建对象时使用;
- 如果一个对象只用一次,后面不再使用,就可以考虑使用匿名对象;
(1)概念
- 包 (package) 是组织类的一种方式,是一组类的集合;
- 使用包的主要目的是保证类的唯一性;
- 在IDEA中创建包时,包名要与其路径相匹配;
- 如果一个类没有 package 语句, 则该类被放到一个默认包中。
(2) 导入包中的类
- 例如同时导入了java.until.Date和java.sql.Date包,如果写Date date = new Date(); 就会出现错误,这是我们可以修改为Date java.until.Date = new java.until.Date();
(3) 静态导入
-
使用 import static 可以导入包中的静态的方法和字段;
-
示例:
import static java.lang.Math.*; public class Test { public static void main(String[] args) { double x = 30; double y = 40; // 静态导入的方式写起来更方便一些. // double result = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); double result = sqrt(pow(x, 2) + pow(y, 2)); System.out.println(result); } }
(4)包的访问权限控制
- 脱离包外不能访问;
- default:包访问权限,在什么都不写的情况下默认为fdfault;
(5)常见的系统包
- java.lang:系统常用基础类(String、Object),此包从JDK1.1后自动导入;
- java.lang.reflect:java 反射编程包;
- java.net:进行网络编程开发包;
- java.sql:进行数据库开发的支持包;
- java.util:是java提供的工具程序包;
- java.io:I/O编程开发包。
(1)概念
- 从程序上:将共性进行抽取,使用关键字extends来继承;
- Java中一个子类只能继承一个父类;
- 子类会继承父类的字段和方法,注意:父类private的字段和方法,子类要想使用需要调用get()和set()方法;
- 子类的实例中包含着父类的实例,可以使用super关键字来得到父类实例的引用;
(1)方法重写的条件
- 函数名称相同;
- 函数的参数列表相同(个数,类型等);
- 函数的返回值相同;也可以不相同,但是返回值之间要构成父子类关系(协变类型);
(2)注意事项
- 静态方法不可以被重写;
- private方法是不可以被重写的;
- 子类的访问权限要大于父类的访问权限;
- 如果一个方法被final修饰,则这个方法就不能被重写;
用于修饰类、属性和方法;
- 被final修饰的类不可以被继承;
- 被final修饰的方法不可以被重写;
- 被final修饰的变量不可以被改变,被final修饰不可变的是变量的引用,而不是引用指向的内容,引用指向的内容是可以改变的;
(1)关键字super表示父类对象的引用,作用如下:
- 访问父类的成员变量;
- 访问父类的成员方法;
- 访问父类的构造方法;
(2)注意
- 子类对象要构造,先要帮助父类对象构造,所有的构造对象都要有构造方法;
- super构造方法要放在第一行;
设置为private不能访问,public 封装不行,两全其美的办法就是protected关键字;
- 对于类的调用者来说, protected 修饰的字段和方法是不能访问的;
- 对于类的子类和同一个包的其他类来说, protected 修饰的字段和方法是可以访问的;
一般情况下,继承最多写三层;如果想从语法上进行限制继承, 就可以使用final 关键字;
7.final关键字- 修饰类,密封类,类不能被继承;例如:String类被final修饰,不能被继承;
- 修饰变量,常量,不能被修改;
- 修饰方法,密封方法,不能被重写;
和继承类似, 组合也是一种表达类之间关系的方式, 也是能够达到代码重用的效果。
-
示例:
public class Student { ... } public class Teacher { ... } public class School { public Student[] students; public Teacher[] teachers; } -
组合并没有涉及到特殊的语法(诸如 extends 这样的关键字), 仅仅是将一个类的实例作为另外一个类的字段;
-
组合表示 has - a 语义 ,可以理解成一个学校中 “包含” 若干学生和教师;
-
继承表示 is - a 语义 ,可以理解成一只猫也 “是” 一种动物。
Bird bird = new Bird("圆圆");
Animal bird2 = bird;
// 或者写成下面的方式
Animal bird2 = new Bird("圆圆");//父类引用 引用了子类的对象
此时 bird2 是一个父类 (Animal) 的引用, 指向一个子类 (Bird) 的实例. 这种写法称为 向上转型;
向上转型之后,只能通过父类的引用访问父类自己特有的属性和方法,不能访问子类特有的属性和方法;
2.向下转型Bird bird = (Bird)animal; //父类的对象给子类引用 bird.fly();
为了让向下转型更安全, 我们可以先判定一下看看 animal 本质上是不是一个 Bird 实例, 再来转换
Animal animal = new Cat("小猫");
if (animal instanceof Bird) { //instanceof可以判定一个引用是否是某个类的实例.是,则返回 true
Bird bird = (Bird)animal;
bird.fly();
}
3.动态绑定
// Animal.java
public class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
public void eat(String food) {
System.out.println("我是一只小动物");
System.out.println(this.name + "正在吃" + food);
}
}
// Bird.java
public class Bird extends Animal {
public Bird(String name) {
super(name);
}
public void eat(String food) {
System.out.println("我是一只小鸟");
System.out.println(this.name + "正在吃" + food);
}
}
// Test.java
public class Test {
public static void main(String[] args) {
Animal animal1 = new Animal("圆圆");
animal1.eat("谷子");
Animal animal2 = new Bird("扁扁");
animal2.eat("谷子");
}
}
// 执行结果
我是一只小动物
圆圆正在吃谷子
我是一只小鸟
扁扁正在吃谷子
当子类和父类中出现同名方法的时候,编译时还是animal.eat()方法,运行时绑定Bird.eat()方法;
4.理解多态(1)只通过一个animal.eat();
(2)引用的对象不同,传递的参数不同;
(3)通过这个引用,调用同一个方法,表现出了不同的形式,这一种情况(思想)叫做多态;
5.在构造方法中调用重写方法class B {
public B() {
// do nothing
func();
}
public void func() {
System.out.println("B.func()");
}
}
class D extends B {
private int num = 1;
@Override
public void func() {
System.out.println("D.func() " + num);
}
}
public class Test {
public static void main(String[] args) {
D d = new D();
}
}
// 执行结果
D.func() 0
//1.构造 D 对象的同时, 会调用 B 的构造方法.
//2.B 的构造方法中调用了 func 方法, 此时会触发动态绑定, 会调用到 D 中的 func
//3.此时 D 对象自身还没有构造, 此时 num 处在未初始化的状态, 值为 0.
建议:尽量不要使用;
五、抽象类 1.抽象类- 包含抽象方法的类,就是抽象类;
- 该方法没有具体的实现,则给方法加上abstract就叫做抽象方法;
(1)抽象类不可以被实例化(new);
(2)抽象类当中也可以有和普通类一样的成员;
(3)一个普通类如果继承了这个抽象类,这个类需要重写这个抽象类当中的抽象方法;
(4)一个抽象类B继承了一个抽象类A之后,可以不重写抽象类A中的抽象方法,但是一旦这个抽象类B被继承后,那么一定要重写所有的抽象方法;
(6)抽象方法是不能被private、static、final修饰的;
4.抽象类的作用- 抽象类存在的最大意义就是为了被继承;
- 多重校验:使用抽象类的场景实际上工作不应该由父类完成, 而应由子类完成. 那么此时如果不小心误用成父类了, 使用普通类编译器是不会报错的,但是父类是抽象类就会在实例化的时候提示错误, 让我们尽早发现问题。
接口是抽象类的更进一步. 抽象类中还可以包含非抽象方法和字段。 而接口中包含的方法都是抽象方法, 字段只能包含 静态常量;
interface IShape {
void draw();
}
class Cycle implements IShape {
@Override
public void draw() {
System.out.println("○");
}
}
public class Test {
public static void main(String[] args) {
IShape shape = new Rect();
shape.draw();
}
}
2.注意事项
(1)使用 interface 定义一个接口;
(2) 接口中的方法,默认全部都是 public、abstract ;
(3)接口当中的成员变量,都是public、static、final;
(4)使用 implements 继承接口. 此时表达的含义不再是 “扩展”, 而是 “实现” ;
(5)接口不能被实例化;
(6)可以同时继承抽象类,也可以同时实现多个接口。但是类只能继承一个;
(7)接口当中,可以有静态方法;
(8)作用:是为了满足Java中多继承的要求;
3.实现多个接口interface IA {
void funcA();//接口的方法默认是public
}
abstract class B implements IA {
public abstract void funcB();
}
interface ID {
void funcD();
}
interface IE {
void funcE();
}
class C extends B implements ID,IE {//顺序不能乱:先继承类,在实现接口
@Override
public void funcA() {
}
@Override
public void funcB() {
}
@Override
public void funcD() {
}
@Override
public void funcE() {
}
}



