Java面向对象编程
Java的核心就是OOP(面向对象)
4、面向对象的三大特性(重点)
封装
-
该露的露,该藏的藏:
- 我们程序设定要追求高内聚,多耦合。
- 高内聚:累的内部数据操作细节自己完成,不允许外部干涉;
- 多耦合:仅暴露少量的方法给外部使用。
-
封装(数据的隐藏)
- 通常应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏。
-
记住一句话:属性私有,get/set
-
下面进行简单的操作:
package com.oop.demo04; public class Student { /* 封装: 1.提高程序的安全性,保护数据 2.隐藏代码的实现细节 3.统一接口 4.增加系统可维护性 */ //private属性私有,不能直接被使用 private String name;//名字 private int age;//学号 private char sex;//性别 //提供一些可以操作这个属性的方法! //提供一些public 的get、set方法 //get 获得这个数据 public String getName(){ return this.name; } //set 给这个数据设置值 public void setName(String name){ this.name = name; } public int getAge(){ return this.age; } //给年龄设置一个范围 public void setAge(int num){ if (age>150||age<0){ this.age = 3; }else { this.age = num; } } public char getSex(){ return this.sex; } public void setSex(char sex){ this.sex = sex; } }
public class Application { public static void main(String[] args) { Student s1 = new Student(); s1.setName("小明"); System.out.println(s1.getName()); s1.setNum(999); System.out.println(s1.getNum()); } }
继承
-
继承的本质是对某一批类的抽象,从而实现对世界更好的建模。
-
extends的意思是"拓展"。子类是父类的拓展。
-
JAVA中类只有单继承,没有多继承!
-
继承是类和类之间的一种关系。除此之外,类和类之间的关系还有依赖、组合、聚合等。
-
继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字extends来表示。
-
子类(派生类)和父类(基类)之间,从意义上讲应该具有**“子类 is 父类”**的关系。
-
下面进行特殊的操作:
- 设置一个父类(基类)Father、两个子类Son和Dau
- 父亲拥有10个亿(私有的private)
- 这时候子类不能直接使用父类的10个亿
- 这时候需要get/set
package com.oop.demo05; //在JAVA中,所有的类都默认直接或者间接继承object //Father:父类/基类 public class Father/*extends object*/ { //private私有的,不能直接被使用,必须get/set private int money = 10_0000_0000; //获取这个数据 public int getMoney(){ return money; } //给这个数据设置值 public void setMoney(int money){ this.money = money; } }
- 然后子类通过extends继承父类
package com.oop.demo05; //son:派生类/子类 //子类继承了父类,就会拥有父亲的全部方法! //son is father public class Son extends Father {}
- 然后可以直接通过子类调用父类的方法
public class Application { public static void main(String[] args) { //使用new关键字,调用构造器 Son son = new Son(); son.getMoney();//获得这个数据 son.setMoney(5000);//设置这个数据 System.out.println(son.getMoney());//输出5000 } }
- 一般情况下父类要给子类调用方法会用public
拓展
object类
- object类:在JAVA中,所有的类都默认直接或者间接继承object
super 详解
下面先进行几个简单的操作:
- 操作一:super 出现在子类的方法(有参)
- 父类
package com.oop.demo06;
public class Father {
protected String name = "songge";
}
- 子类
package com.oop.demo06;
public class Son extends Father {
String name = "tongxin";
public void say(String name){
//传递参数name;
System.out.println(name);
//直接调用这个类的name;
System.out.println(this.name);//tongxin
//super调用了父类的name;
System.out.println(super.name);//songge
}
}
- 输出
public class Application {
public static void main(String[] args) {
Son son = new Son();
son.say("松哥");
}
}
- 运行后显示
- 操作二:super 出现在子类的方法(无参)
- 父类
package com.oop.demo06;
public class Father {
public void test(){
System.out.println("tongxin");
}
}
- 子类
package com.oop.demo06;
public class Son extends Father {
public void test(){
System.out.println("songge");
}
public void say1(){
test();//调用这个类的test;
this.test();//调用这个类的test;
super.test();//调用父类的test;
}
}
- 输出
public class Application {
public static void main(String[] args) {
Son son = new Son();
son.say1();
}
}
- 运行后显示
- 操作二:super 调用父类的构造方法(无参)
- 父类
package com.oop.demo06;
public class Father {
//父类的无参构造
public Father() {
System.out.println("Father无参构造");
}
}
- 子类
package com.oop.demo06;
public class Son extends Father {
public Son() {
//运行后先输出了父类的无参构造,然后输出了子类的无参构造
//说明这里隐藏了代码:super();默认调用了父类的无参构造
System.out.println("Son无参构造");
}
}
- 输出
public class Application {
public static void main(String[] args) {
Son son = new Son();
}
}
- 运行后显示
super总结 :
super注意点:
1.super 调用父类的构造方法,必须在构造方法的第一个
2.super 只能出现在子类的方法或者构造方法中!
3.super 和 this 不能同时调用构造方法!
super和this对比:
1.代表的对象不同
- this : 本身调用者这个对象
- super: 代表父类对象的应用
2.前提:
- this : 没有继承也能使用
- super: 只能在继承条件下使用
3.
- this() : 本类的构造
- super(): 父类的构造
方法重写
下面先进行几个简单的操作:
- 操作一:当调用方法是静态方法的时候,不存在重写
- 父类
package com.oop.demo07;
public class A {
public static void test() {
System.out.println("A is num1");
}
}
- 子类
package com.oop.demo07;
//继承关系
//静态方法的时候
public class B extends A{
public static void test(){
System.out.println("B is num1");
}
}
- 输出
package com.oop.demo07;
public class Application {
public static void main(String[] args) {
//当静态方法的时候,不存在重写
//方法的调用只和左边定义的数据类型有关
A a = new B();
a.test();//输出A
//父类的引用指向了子类
B b = new B();
b.test();//输出B
}
}
- 运行后显示
-
操作二:当调用方法是非静态方法的时候,才会存在重写
- 父类
package com.oop.demo07; //重写都是方法的重写,和属性无关 public class A { public void test(){ System.out.println("A--a"); } }
- 子类
package com.oop.demo07; //继承关系 public class B extends A{ //快捷键Alt+Insert --> Override //Override 重写 @Override//注解:有功能的注释! public void test() { System.out.println("B--b"); } }
- 输出
public class Application { public static void main(String[] args) { //当非静态方法的时候,才有重写 //子类重写了父类的方法 A a = new B(); a.test();//输出B B b = new B(); b.test();//输出B } }
- 运行后显示
重写总结
重写:需要有继承关系,子类重写父类的方法!
1.方法名必须相同
2.参数列表必须相同
3.修饰符:范围可以扩大:
Public>Protectded>Default>Private
4.抛出的异常:范围可以被缩小,但不能被扩大
classNotFoundException-->FoundException(范围特别大)
重写:子类的方法和父类的方法必须要一致,方法体不同
重写的意义:
1.父类的功能子类不一定需要/满足
2.快捷键Alt+Insert--->Override
多态
-
即同一个方法可以根据发送对象的不同而采取多种不同的行为方式。
-
一个对象的实际类型是确定的,但可以指向对象的引用的类型(父类/有关系的类)有很多。
-
多态注意事项:
- 多态是方法的多态,属性没有多态性。
- 必须是有联系的类,父类与子类之间
- 如果是没有关系的两个类,会出现类型转换异常!:ClassCastException!
- 多态存在的条件:
- 有继承关系
- 子类重写父类方法
- 父类引用指向子类对象!
- 有些方法不能被重写:
- 静态方法,含static的方法,他属于类,不属于实例;
- final 常量;
- 属性私有的方法,含private的方法
-
下面先进行简单的操作:
- 父类
package com.oop.demo08; public class Person { public void say(){ System.out.println("我是谁!"); } }
- 子类
package com.oop.demo08; public class Student extends Person{ //重写父类的方法 public void say(){ System.out.println("谁是我"); } //子类独有的方法 public void eat(){ System.out.println("美味!"); } }
- 输出
import com.oop.demo08.Student; import com.oop.demo08.Person; public class Application { public static void main(String[] args) { /* 一个对象的实际类型是确定的 例如 Student student = new Student(); Person person = new Person(); */ //可以指向的引用类型就不确定了:父类引用指向子类 //对象能执行哪些方法,主要看对象左边的类型,和右边关系不大! //Student能调用的方法都是自己的或者继承父类的! Student s1 = new Student(); //Person 父类型,可以指向子类,但是不能调用子类独有的方法 Person s2 = new Student(); Object s3 = new Student(); //子类执行自己的方法 s1.say();//输出 谁是我 //子类重写了父类的方法,执行子类的方法 s2.say();//输出 谁是我 //子类执行自己的方法 s1.eat();//输出 美味! //父类想要执行子类独有的方法,把父类强行转换为子类,高转低 ((Student)s2).eat();//输出 美味! } }
-
instanceof (类型转换) 引用类型
- 主要公式:System.out.println(A instanceof B);
- 看代码能否编译通过
- 取决于是否存在父子关系
- 下面进行简单操作:
public class Application { public static void main(String[] args) { //Object>String //Object>Person>Student //Object>Person>Teacher //看代码能不能编译通过! //取决于是否存在父子关系 //System.out.println(A instanceof B); Object object = new Student(); System.out.println(object instanceof Object);//true System.out.println(object instanceof Person);//true System.out.println(object instanceof Student);//true System.out.println(object instanceof Teacher);//false System.out.println(object instanceof String);//false System.out.println("========================="); Person person = new Student(); System.out.println(person instanceof Object);//true System.out.println(person instanceof Person);//true System.out.println(person instanceof Student);//true System.out.println(person instanceof Teacher);//false //System.out.println(person instanceof String);//编译报错! System.out.println("========================="); Student student = new Student(); System.out.println(student instanceof Object);//true System.out.println(student instanceof Person);//true System.out.println(student instanceof Student);//true //System.out.println(student instanceof Teacher);//编译报错! //System.out.println(student instanceof String);//编译报错! } }
-
类型转换
- 父类引用指向子类的对象
- 把子类转换为父类自动转换:低转高,可能会丢失一些方法
- 把父类转换为子类强制转换:高转低,
- 类型转换为了方便方法的调用,减少重复的代码!
- 下面进行简单的操作
package com.oop.demo09; public class Application { public static void main(String[] args) { //父类person引用指向Student,但是不能用子类独有的方法 Person person = new Student(); //这时候要先将person类强制转换为Student类 //转换好的person1可以直接使用子类独有的方法 Student person1 = (Student) person; person1.say(); //一般直接将person强制转换为Student类型 //这样可以直接使用子类独有的方法 ((Student)person).say(); } }
Static关键字详解
-
被static修饰的方法或变量随着类加载的时候就加载了,可以不用new对象,直接调用
- 静态的变量
package com.oop.demo10; //static public class Student { //静态变量 static //随着类加载的时候就加载了,可以不用new对象,直接调用 private static int age; private double score;//非静态的变量 public static void main(String[] args) { Student s1 = new Student(); System.out.println(Student.age); //System.out.println(Student.score);//不能直接调用 System.out.println(s1.age); System.out.println(s1.score); } }
- 静态的方法
package com.oop.demo10; public class Teacher { //非静态方法 public void say(){ go();//非静态方法可以直接调用静态方法 System.out.println("来"); } //静态方法 static //随着类加载的时候就加载了,可以不用new对象,直接调用 public static void go(){ System.out.println("走"); } public static void main(String[] args) { go();//直接调用 new Teacher().say();//不能直接调用 } }
-
静态代码块
- 可以加载一些初始化的东西
- 静态代码块跟类加载的时候一起执行
- 最开始执行并只执行一次
package com.oop.demo10; public class Person { /* 2.匿名代码块: - 附初始值 - 跟对象同时产生,在构造方法之前 */ { System.out.println("匿名代码块"); } /* 1.静态代码块: - 可以加载一些初始化的东西 - 静态代码块跟类加载的时候一起执行 - 最开始执行并只执行一次 */ static { System.out.println("静态代码块"); } //3.构造方法 public Person(){ System.out.println("构造方法"); } public static void main(String[] args) { Person person = new Person(); System.out.println("========="); Person person1 = new Person(); } }
- 运行后显示:
-
静态的导入包
- 没有导入random的时候必须输入Math.random
public class Application { public static void main(String[] args) { System.out.println(Math.random()); } }
- 但是不能直接导入到random,可以加个static变成静态导入包,这样可以直接使用random
//静态导入包 import static java.lang.Math.random; import static java.lang.Math.PI; public class Application { public static void main(String[] args) { System.out.println(random()); System.out.println(PI); } }