面向对象编程
1.初识面向对象
-
面向过程思想:是一种线性思维,步骤清晰简单,第一步->第二步->第三步…
面向对象思想:是一种分类的思维模式,将要解决的问题分类,再对这些类单独思考。
-
面向对象编程(OOP)的本质:以类的方式组织代码,以对象的组织(封装)数据。
-
类是一组相关属性和行为的集合,可以看成一类事务的模板,使用事物的属性特征和行为特征描述该类事物。(在Java中简单点说就是:类=属性+方法)
对象是一类事物的具体体现。对象是类的一个实例,必然具备事物的属性和行为。
-
类与对象的关系:类是一类事物的描述,是抽象的;对象是一类事物的实例,是具体的;类是对象的模板,对象是类的实体。
类与对象的创建:
public class Demo01 {
public static void main(String[] args) {
//类实例化会返回自己的对象,student对象就是Student类的实例
Student student=new Student();
//给对象name属性赋值
student1.name="桥本环奈";
System.out.println(student.name);
}
}
//学生类
class Student{
String name;
public void study(){
System.out.println(this.name+"在学习");
}
}
-
使用new关键字创建对象的时候,除了分配内存空间,还会给创建好的对象进行默认的初始化以及对类中构造器(也叫构造方法)的调用。
public class Demo01 { public static void main(String[] args) { //类实例化会返回自己的对象,student1和student2对象就是Student类的实例 Student student1=new Student(); Student student2=new Student(); //给对象name属性赋值 System.out.println(student1.name); //输出为初始化null System.out.println(student2.name); //输出为初始化null student1.name="桥本环奈"; student2.name="大姐大"; System.out.println(student1.name); //输出为桥本环奈 System.out.println(student2.name); //输出为大姐大 } } //学生类模板 class Student{ //构造器(也叫构造方法):创建对象的时候(即new了一个对象),会自动执行一次构造方法 //构造器特点:1.必须和类名保持一致。2.必须没有返回类型,也不能写void //构造器作用:属性进行初始化赋值; public Student(){ //这是一个默认构造方法(无参无返回值),创教对象时即使没写也会执行该默认方法 } String name; public Student(){ this.name="哇哈哈"; //初始化赋值 } public void study(){ System.out.println(this.name+"在学习"); } }
2.面向对象三大特性
2.1 封装
-
面向对象三大特性:封装、继承、多态。
-
程序设计要求:高内聚,低耦合
高内聚,低耦合:高内聚指类的内部数据操作细节自己完成,不允许外部干涉;低耦合指类仅暴露少量的方法给外部使用。
-
封装:数据的隐藏;通常应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏。
Java封装记住:属性私有,get/set
public class Demo02 { public static void main(String[] args) { Student1 student1=new Student1(); student1.setName("桥本环奈"); student1.setAge(18); System.out.println(student1.getName()); System.out.println(student1.getAge()); } } //Student1类 属性私有(private) 调用属性使用get与set方法 class Student1{ 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; } }
-
封装的意义:
- 提高程序的安全性,保护数据
- 隐藏代码的实现细节
- 统一接口(get/set)
- 系统的可维护性增加了
2.2 继承
-
继承是类与类之间的关系,继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用extends表示。
-
extends有扩展的意思。子类是父类的扩展。
-
所有类,或直接、或间接继承Object类。
-
私有的(private)的变量和方法无法被继承。
-
子类构造器中会默认先调用父类构造器。(无参构造调无参构造,有参构造调有参构造)
//Student is 人(Person) public class Student extends Person{} //Person为父类,Student为子类 //Teacher is 人(Person) public class Teacher extends Person{} //Person为父类,Teacher为子类
子类继承了父类,子类就会拥有父类的全部方法。 public class Person { int money=100; public void method(){ System.out.println("我有"+money+"元"); } } public class Teacher extends Person{ //子类默认继承了父类Person类的money属性和method方法 }
子类构造器中会默认先调用父类构造器。 public class Person { public Person{ System.out.println("Person"); } } public class Teacher extends Person{ public Teacher{ //在Teacher无参构造方法中,会默认使用super调用父类无参构造方法 //super(); 要在构造方法第一行 System.out.println("Teacher"); } } 输出结果为:Person Teacher
-
super与this关键字
super注意点:
- super调用父类的构造方法,必须在构造方法的第一个
- super 必须只能出现在子类的方法或者构造方法中!
- super和 this不能同时调用构造方法!
this:
-
代表的对象不同:
this:本身调用者这个对象
super:代表父类对象的应用
-
前提
this:没有继承也可以使用
super:只能在继承条件才可以使用 -
构造方法
this();本类的构造 super():父类的构造
public class Person { protected String name="fu"; public void mm(){ System.out.println("Person"); } } public class Teacher extends Person{ private String name="zi"; public void mm(){ System.out.println("Teacher"); } public void method(){ String name="di"; System.out.println(name); //这里的name指方法中局部变量name,输出为di System.out.println(this.name); //这里的this.name指本类中成员变量name,输出为zi System.out.println(super.name); //这里的super.name指本类的父类中存在的同名变量name,输出为fu } public void method2(){ mm(); //这里的mm方法指本类中的成员方法mm(),输出为Teacher this.mm(); //这里的this.mm方法同样指本类中的成员方法mm(),输出为Teacher super.mm(); //这里的super.mm方法指本类的父类中的成员方法mm(),输出为Person } }
-
方法的重写(重写都是方法的重写,和属性无关)
-
重写:需要有继承关系,子类重写父类的方法。非静态方法可以重写
- 方法名必须相同
- 参数列表必须相同
- 修饰符:范围i可以扩大但不能缩小 public>protected>default>private
- 抛出的异常:可以缩小但不能扩大
public class Person { public void mm(){ System.out.println("Person"); } } public class Teacher extends Person{ @Override public void mm(){ //重写了父类的mm()方法 System.out.println("Student"); }
2.3 多态
- 多态是方法的多态,属性没有多态
- 存在条件:继承关系,方法需要重写,父类引用指向子类对象.(注意static静态方法是属于类的,不能被重写;私有方法也不能重写;final常量不能被重写)
public class Person {
public void test(){
System.out.println("fu");
}
public void p(){
System.out.println("Person");
}
}
public class Student extends Person{
public void test(){
System.out.println("zi");
}
public void s(){
System.out.println("Student");
}
}
public class app {
public static void main(String[] args) {
//父类的引用指向子类
//对象能执行哪些方法,主要看左边中的类型有什么方法
//Student类调用的方法只能是自己的或者继承父类的方法
Student student=new Student(); 左边是Student可以执行test(),s(),p()方法
//Person类,父类型:可以指向子类,但不能调用子类独有的方法(子类有父类没有的方法),
Person person=new Student(); 左边是Person可以执行test()和p()方法,但test()被子类重写执行子类方法体
student.test(); //自己调用自己,执行自己的方法,输出为zi
person.test(); //父类的引用指向子类,父类子类共有方法test,执行子类重写的方法,输出为zi
student.s(); //这是子类独有的方法s(),父类没有,父类不能执行此方法,只有子类自己调用,输出为Student
student.p(); //子类继承自父类的方法p(),输出为Person
person.p(); //父类独有方法可以被子类继承,输出为Person
}
}
-
instanceof关键字(判断类是否有父子)
public class Person { public void run(){ System.out.println("run"); } } public class Student extends Person{ public void go(){ System.out.println("go"); } } public class Teacher { } public class app { public static void main(String[] args) { //Object -> Person ->Student Object object=new Student(); //祖父引用指向子类对象,一条关系链Object指向Person指向Student //instanceof关键字,X instanceof Y; X是否与Y存在父子关系 System.out.println(object instanceof Student); //在上面关系链当中,object与Student存在父子关系,输出为true System.out.println(object instanceof Person); //在上面关系链当中,object与Person存在父子关系,输出为true System.out.println(object instanceof Object); //在上面关系链当中,object与Object存在父子关系,输出为true System.out.println(object instanceof Teacher); //不在上面关系链当中,object与Teacher不存在父子关系,输出为false System.out.println(object instanceof String); //不在上面关系链当中,object与String不存在父子关系,输出为false //类型之间的转换:父 子 //父类转换为子类,向下转型需要强制转换 Person person=new Student(); ((Student)person).go(); //person是Person类型不可以执行go()方法,将person类型转换为Student类型就可以执行go()方法。 //子类转换为父类,向上转型不需要强制转换,但可能会丢失一些子类本来的方法,如下面的转换丢失了go()方法 Student student=new Student(); Person p=student; } }
-
static关键字详解
public class Student { private static int age; //静态变量 private double score; //非静态变量 public static void run(){ //静态方法 System.out.println("run"); } public void go(){ //非静态方法 System.out.println("go"); } static { //静态代码块,类加载时执行一次,并且仅执行一次;记住静态代码块比匿名代码块先执行,匿名代码块又比构造方法先执行 System.out.println("这是静态代码块,永久且仅执行一次"); } { //匿名代码块,类加载时执行,可以执行多次 System.out.println("这是一个匿名代码块"); } public static void main(String[] args) { Student student=new Student(); //静态变量与非静态变量 //静态变量可以通过 类名.变量名 直接调用,也可以通过实例化对象来调用 System.out.println(Student.age); System.out.println(student.age); //非静态变量需要通过实例化对象才可以调用,不可以通过 类名.方法名 来调用 System.out.println(student.score); //静态方法与非静态方法 //静态方法可以通过 类名.方法名 直接调用,也可以通过实例化对象来调用 Student.run(); student.run(); //非静态方法可以通过实例化对象来调用,不可以通过 类名.方法名 来调用 student.go(); } }
3.抽象类和接口
3.1 抽象类
-
abstract修饰符可以用来修饰方法也可以修饰类,如果修饰方法那么该方法就是抽象方法,如果修饰类那么该类就是修饰类。
-
抽象类中可以没有抽象方法,但是有抽象方法的类一定是抽象类。
-
抽象类中既可以有抽象方法,也可以有普通方法。
-
不能new抽象类(即不能实例化),只能靠子类去实现抽象类。
-
抽象类只能单继承(A extends B),不能多继承。
//abstract 抽象类 public abstract class A { //abstract,抽象方法:只有方法的名字,没有方法的实现 public abstract void doSome(); } //抽象类的子类(称为实现类)需要实现抽象类的所有抽象方法,除非子类还是抽象类。 public class B extends A{ @Override public void doSome() { System.out.println("DoSome"); } }
3.2 接口
-
interface定义接口,接口都要有实现类
-
接口可以多继承(A implements B,C)
-
接口不能被实例化,接口中没有构造方法
-
接口中的方法都是抽象方法
//interface定义接口,接口都要有实现类 public interface A { //接口中的所有定义的方法其实都是抽象的, public abstract //public abstract void run(); 其中public abstract可以省略,因为都是抽象的 void run(); void go(); } //类可以实现接口,implements 接口 //实现接口的类需要重写接口中的方法 public class AImpl implements A{ @Override public void run() { System.out.println("run"); } @Override public void go() { System.out.println("go"); } }
4.内部类
-
内部类就是在一个类的内部再定义一个类。
-
包括:
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
展示成员内部类和静态内部类: public class Outer { private int id=10; public void out(){ System.out.println("这是外部类的方法"); } public class Inner{ //成员内部类,在类中在方法外 //public static class Inne{} 静态内部类,比变量方法先执行,所以不用于获取外部类私有属性 public void in(){ System.out.println("这是一个成员内部类的方法"); } //内部类可以获得外部类的私有属性和私有方法 public void getId(){ System.out.println(id); } } } public class app { public static void main(String[] args) { //实例化外部类 Outer outer=new Outer(); //通过外部类实例化内部类 Outer.Inner inner=outer.new Inner(); inner.getId(); //通过内部类调用外部类私有属性 } }
展示局部内部类: public class Outer { public void method(){ class Inner{ //局部内部类,在方法中的类 public void in(){ System.out.println("这是一个局部内部类"); } } } }
展示匿名内部类: public class Test { public static void main(String[] args) { //没有名字初始化类,不用将实例保存到变量中 new A().method(); } } class A{ public void method(){ System.out.println("匿名内部类"); } }