1.封装(是对类/对象的封装,类是对一类事物的整体描述)
-
该露的露,该藏的藏
- 我们程序设计要追求 **“高内聚,低耦合” ** 。
- 高内聚:就是类的内部数据操作细节自己完成,不允许外部干涉。
- 低耦合:仅暴露少量的方法给外部使用。
-
封装(数据的隐藏)
- 通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏。
-
记住这句话就够了:属性私有, get/set
代码如下:
package com.wlw.oop.demo04;
//封装
//属性私有 : private
/*
一般我们都会把属性私有,
这样在其他方法中,创建出来的对象,
不能通过 对象名.属性名 来直接使用,
只能通过这个类留出来的public的get/set方法来操作属性,
这就是,高内聚,低耦合,的一种表现
*/
public class Student {
private String name;
private int age;
private int id;//学号
private char sex;
public String getName(){
return this.name;
}
public void setName(String name){
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if(age > 120 || age < 0){
System.out.print("你输入的年龄不合法,我怀疑你的年龄只有3岁!");
this.age = 3;
}else {
this.age = age;
}
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
}
package com.wlw.oop.demo04;
public class Application {
/*封装的意义:
1.提高程序的安全性,保护数据
2.隐藏代码的是实现细节
3.统一接口
4.提高系统的可维护性
*/
public static void main(String[] args) {
Student s1 = new Student();
s1.setName("大海");
System.out.println(s1.getName()); //大海
s1.setAge(999);
System.out.println(s1.getAge()); //你输入的年龄不合法,我怀疑你的年龄只有3岁!3
}
}
IDEA快捷键,Alt + Insert,可以自动生成get/set方法,还有构造器,以及下面的方法重写
2.继承(对某一批类的抽象)
-
继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模。
-
extends的意思是”扩展”。子类是父类的扩展。
-
JAVA中类只有单继承,没有多继承!(一个子类只能有一个父类,而一个父类可以用多个子类)
-
继承是类和类之间的一种关系。除此之外,类和类之间的关系还有依赖、组合、聚合等。
-
继承关系的俩个类,一个为子类(派生类),一个为父类(基类)。 子类继承父类,使用关键字extends来表示。
-
子类和父类之间,从意义上讲应该具有"is a"的关系.(子类默认继承父类(public)方法)
package com.wlw.oop.demo05; //在java中,所有的类,都默认直接或间接继承object类。 //Person 人 :父类(基类) public class Person { //public 公共的 //protected 受保护的 //default 默认的 //private 私有的 私有的东西无法被继承 private int money = 10_0000_0000; public void say(){ System.out.println("说了一句话"); } public int getMoney() { return money; } public void setMoney(int money) { this.money = money; } }
package com.wlw.oop.demo05; // Student is a Person //子类(派生类) public class Student extends Person { }
package com.wlw.oop; import com.wlw.oop.demo05.Student; public class Application { public static void main(String[] args) { Student s1 = new Student(); s1.say(); //说了一句话 System.out.println(s1.getMoney()); //1000000000 } }
2.1object类
在java中,所有的类,都默认直接或间接继承object类。
2.2super(父)
super注意点:
-
super调用父类的构造方法,必须在构造方法的第一行
-
super 必须只能出现在子类的方法或者构造方法中
-
super和this不能同时调用构造方法
VS this:
-
代表的对象不同:this:本身调用者这个对象;super:代表父类对象的引用
-
前提:this:没有继承也能使用;super:只能在继承条件下才能使用
-
构造方法:this:本类的构造;super:父类的构造!
package com.wlw.oop.demo05;
//在java中,所有的类,都默认直接或间接继承object类。
//Person 人 :父类(基类)
public class Person {
public Person() {
System.out.println("Person无参构造");
}
protected String name = "大海Person";
public void print(){
System.out.println("Person");
}
}
package com.wlw.oop.demo05;
// Student is a Person
//子类(派生类)
public class Student extends Person {
public Student() {
//默认调用父类的无参构造,即下一句
super();
System.out.println("Student无参构造");
}
private String name = "大海Student";
public void print() {
System.out.println("Student");
}
public void test1(){
print(); //Student
this.print(); //Student
super.print(); //Person
}
public void test(String name){
System.out.println(name); //大海main
System.out.println(this.name); //大海Student
System.out.println(super.name); //大海Person
}
}
package com.wlw.oop;
import com.wlw.oop.demo05.Student;
public class Application {
public static void main(String[] args) {
Student s1 = new Student();
// s1.test("大海main");
s1.test1();
Student s2 = new Student();
//这一行的输出结果:
/*
Person无参构造
Student无参构造
*/
}
}
2.3方法重写(与继承密切相关,注意区分 方法重载 )
- 重写都是方法的重写,和属性无关
- 方法重写只与非静态方法有关(与静态方法无关,因为static静态方法在类加载时,就已经加载了)
- private的方法是无法重写的,重写的方法(一般)都是public的,protected的方法也能重写
- 注意点:
- 需要有继承关系,子类重写父类的方法 (而方法重载只是一个类中方法)
2. 方法名必须相同
3. 参数列表必须相同 (方法重载却是方法名相同,而参数不同)
4. 修饰符:范围可以扩大但不能缩小 public > protected > default > private
5. 方法重写只与非静态方法有关
6. 抛出的异常:范围可以被缩小,但不能扩大
7. 重写,子类的方法和父类必须一致,方法体不同 - 为什么需要重写:
- 父类的功能,子类不一定需要,或者不满足
- 快捷键:Alt + Insert (这个里面有很多功能的快捷键)
// 静态方法
//方法的调用只与左边,定义的数据类型有关
package com.wlw.oop.demo05;
public class B {
public static void test(){
System.out.println("B===>text()");
}
}
package com.wlw.oop.demo05;
public class A extends B{
public static void test(){
System.out.println("A===>text()");
}
}
package com.wlw.oop;
import com.wlw.oop.demo05.A;
import com.wlw.oop.demo05.B;
public class Application {
public static void main(String[] args) {
// 静态方法
//方法的调用只与左边,定义的数据类型有关
A a = new A();
a.test(); //A===>text()
//父类的引用指向子类
B b = new A();
b.test(); //B===>text()
}
}
/*
结果:
A===>text()
B===>text()
*/
//非静态方法,可以重写
//静态方法与非静态方法区别很大
//静态方法: 方法的调用只与左边,定义的数据类型有关
//非静态方法,可以重写
package com.wlw.oop.demo05;
public class B {
public void test(){
System.out.println("B===>text()");
}
}
package com.wlw.oop.demo05;
public class A extends B{
// @Override:重写
@Override //注解: 有功能的注释
public void test() {
System.out.println("A===>text()");
}
}
package com.wlw.oop;
import com.wlw.oop.demo05.A;
import com.wlw.oop.demo05.B;
public class Application {
public static void main(String[] args) {
A a = new A();
a.test(); //A===>text()
B b = new A(); //子类重写了父类的方法
b.test();//A===>text()
}
}
/*
输出结果:
A===>text()
A===>text()
(因为 A 是 B 的子类, test() 这个方法是非静态的,修饰符是public ,所以方法重写了)
*/
2.4public protected default private 权限
-
public: 具有最大的访问权限,可以访问任何一个在classpath下的类、接口、异常等等。它往往用于对外提供调用的形式。
-
protected:主要用来保护子类,它所修饰的属性,方法,可由子类继承
-
default:它是针对本包访问而设计的,任何处于本包下的类,接口,异常等,都可以相互访问。
-
private:访问权限仅限于类的内部,是一种封装的体现。私有的东西无法被继承
3.多态(方法的多态)
-
动态编译:让类型的可扩展性更强。
-
即同一方法可以根据发送对象的不同而采用多种不同的行为方式。
-
一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多(父类,有关系的类)
-
多态注意事项:
- 多态是方法的多态,属性没有多态性
- 有继承关系,才会有父类与子类,两个类之间才有关系(没有关系是无法转换的,类型转换异常 ClassCastException!)
- 存在条件:
- 继承关系
- 方法需要重写
- 父类引用指向子类对象(Father s = new Son();)
- 方法重写注意点:有 static(属于类,不属于实例),final,private修饰的方法不能重写
-
自己的总结:
- 一个方法,如果只有子类有,父类没有,那子类引用可以直接调用,父类引用不能直接调用(需要强转才为子类才能调用)
- 如果一个方法,子类与父类都有,只要子类没有重写该方法,那么子类引用与父类引用就调用父类的该方法;那子类重写了该方法,子类引用与父类引用就调用的是子类里的该方法。(这里说的“子类引用与父类引用就调用的是子类里的该方法”,要注意一个前提:父类引用指向子类实例)
代码如下:
package com.wlw.oop.demo06;
//父类
public class Person {
public void run(){
System.out.println("Person===run");
}
}
package com.wlw.oop.demo06;
//子类
public class Student extends Person {
@Override
public void run() {
System.out.println("Student====run");
}
public void eat(){
System.out.println("该eat()方法只有Student里有");
}
}
package com.wlw.oop.demo06;
public class Application {
public static void main(String[] args) {
//一个对象的实际类型是确定的,new的是什么,它就是什么
//new Student();
//new Person();
//但可以指向的引用类型就不确定了,(多态)
//这是因为 父类的引用可以指向子类
//通过父类来new子类
//一个类的实际对象的类型是确定的: new Student(); 都是Student
//但是可以指向这个对象的引用类型却可以是多个类型(Studnet的父类型)
Student s1 = new Student();
Person s2 = new Student();
Object s3 = new Student();
s2.run();
//1.如果,Student类没有重写run()方法,那么该语句执行的就是Person类里的run()方法,执行结果为:Person===run
//2.如果,Student类重写run()方法,那么该语句执行的就是Student类里的run()方法,执行结果为:Student====run (这是方法重写)
s1.run();
//1.如果,Student类没有重写run()方法,那么该语句执行的就是Person类里的run()方法,执行结果为:Person===run (这是子类默认继承父类方法)
//2.如果,Student类重写run()方法,那么该语句执行的就是Student类里的run()方法,执行结果为:Student====run
//s2.eat();//报错 //((Student)s2).eat();强制转换(高转低) 这样才能执行Student里的eat()方法
//对象能执行哪些方法,主要看对象左边的类型,和右边(new Student();)关系不大
//子类(这里是Student类)能调用的方法都是自己的,或者是继承父类的
//父类(这里是Person类)可以指向子类,但是不能调用子类独有的方法
s1.eat(); //执行结果为:该eat()方法只有Student里有
}
}
/*
执行结果:
Student====run
Student====run
该eat()方法只有Student里有
*/
4.instanceof
判断一个对象是什么类型
instanceof运算符是用来在运行时指出对象是否是特定类的一个实例。
instanceof通过返回一个布尔值来标识该对象是否为特定类或者它的子类的一个实例。
//Person 是父类,Student Teacher 是Person的子类
package com.wlw.oop.demo07;
//父类
public class Person {
public void run(){
System.out.println("Person===run");
}
}
package com.wlw.oop.demo07;
//子类
public class Student extends Person {}
package com.wlw.oop.demo07;
//子类
public class Teacher extends Person {}
package com.wlw.oop.demo07;
public class Application {
public static void main(String[] args) {
// Object > String
// Object > Person > Teacher
// Object > Person > Student
// System.out.println(X instanceof Y); //能不能编译通过!
Object object = new Student();
System.out.println(object instanceof Student); //true
System.out.println(object instanceof Person); //true
System.out.println(object instanceof Object); //true
System.out.println(object instanceof Teacher); //flase
System.out.println(object instanceof String); //fasle
System.out.println("========================");
Person person = new Student();
System.out.println(person instanceof Student); //true
System.out.println(person instanceof Person); //true
System.out.println(person instanceof Object); //true
System.out.println(person instanceof Teacher); //flase
// System.out.println(person instanceof String); //编译错误
System.out.println("========================");
Student student = new Student();
System.out.println(student instanceof Student); //true
System.out.println(student instanceof Person); //true
System.out.println(student instanceof Object); //true
// System.out.println(student instanceof Teacher); //编译错误
// System.out.println(student instanceof String); //编译错误
System.out.println("========================");
}
}
5.类型转换
- 类型之间的转换: 基本类型: 高到低(强制转换), 低到高(自然转换)
- 父类(高) 子类(低)
- 把子类转换成父类,向上转型(自然转换)
- 把父类转换成子类,向下转型(强制转换) 前提:父类的引用指向子类的对象,之后才能向下转型
- 方便方法的调用,减少重复的代码!
package com.wlw.oop.demo07;
//父类
public class Person {
public void run(){
System.out.println("Person===run");
}
}
package com.wlw.oop.demo07;
//子类
public class Student extends Person {
public void go(){
System.out.println("Student里的go方法");
}
}
package com.wlw.oop.demo07;
public class Application {
public static void main(String[] args) {
//类型之间的转换: 基本类型: 高到低(强制转换), 低到高(自然转换)
// 父类(高) 子类(低): 父--->子(强制转换) , 子--->父(自然转换)
//高 <------- 低 这是从低到高,赋值语句,从右往左看(自然转换)
Person person = new Student();
// Person person = new Person(); //会报类型转换错误
//我们将person这个对象 转换成Student类型,才能使用Student类里的方法(强制转换)
Student student = (Student) person;
student.go(); //执行结果:Student里的go方法
//((Student)person).go(); 简单写法
System.out.println("=======================================");
//子类转换成父类,可能丢失自己本来的一些方法!
Student s1 = new Student();
s1.go(); //执行结果:Student里的go方法
s1.run();//执行结果:Person===run
Person p1 = s1; //自然转换
//p1.go();//报错
p1.run();//执行结果:Person===run
}
}
/*
/执行结果:
Student里的go方法
=======================================
Student里的go方法
Person===run
Person===run
*/
6.static关键字详解
6.1静态变量与非静态变量、静态方法与非静态方法
package com.wlw.oop.demo08;
// static
public class Student {
private static int age; //静态变量, (后面 多线程 也会用到)
private double score; //非静态变量
public void run(){ //非静态方法 不可以直接调用,需要通过对象来调用
go();
Student.go();
}
public static void go(){ //静态方法 是可以直接调用的
new Student().run();
}
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);
//1.调用静态方法有两种方式: (1)直接方法名、(2)类名.方法名、(3)对象.方法名
go();
Student.go();
new Student().go(); // s1.go();
//2.调用非静态方法:对象.方法名
new Student().run(); // s1.run();
}
}
6.1.1非静态方法 与静态方法的调用问题
在同一个类中
-
非静态方法可以直接调用静态方法,静态方法不能直接用非静态方法
-
因为static 是和类一起加载的,当类存在时,加static的方法也就存在了,而此时非静态方法还没有被加载,是不存在的; 没有加static的方法,需要 类实例化(new出来一个) 之后,才能存在;
-
但是在静态方法中可以实例化这个类,再调非静态方法,是可以的,因为实例化类了,但是一般不这么做
-
同一个类中,在非静态方法可以调用静态方法的方式:方法名、类名.方法名、实例化对象来调用(不建议)
package com.wlw.chapter5_oop.demo01; public class Student { //静态方法 加修饰符static public static void say(){ System.out.println(" 静态方法 学生说话了"); // read(); //这样报错,静态方法不能直接用非静态方法 new Student().read();//可以先实例化 本类,再调用非静态方法 } //非静态方法 没有加修饰符static public void read(){ System.out.println(" 非静态方法 学生在读书"); say(); //非静态方法可以直接调用静态方法,也可以用 类名.say()来调用 Student.say(); } }
在不同类中
-
在不同类中两种方法的调用方式为:
- 非静态方法: 先实例化这个类,用 new,再通知实例化对象来调用非静态方法
- 静态方法: 类名.方法名 ,当然也可以通过实例化对象来调,不过不建议使用,因为它属于非静态调用的方式
-
在Demo2这个类中,
-
Demo2类中的静态方法,是可以调用Student这个类的静态方法与非静态方法(要注意上面的调用方式)
- Demo2类中的非静态方法同上
package com.wlw.chapter5_oop.demo01;
public class Demo02 {
public static void main(String[] args) {
//这里用的Student就是上面1.1中的Student
//静态方法的调用
System.out.println("静态方法的调用");
Student.say();
//非静态方法的调用
//先实例化这个类,用 new
System.out.println("\n"+"非静态方法的调用");
//对象类型 对象名 = 对象值
Student student = new Student();
student.read();
}
/*
static
1. a和b两个方法,如果都没有加修饰符static,他们之间可以互相调用
2. a和b两个方法,如果都加了修饰符static,他们之间也可以互相调用
3. a和b两个方法,有一个没加,另一个加了,在同一个类中,非静态方法可以直接调用静态方法,静态方法不能直接用非静态方法(但是可以实例化这个类,再调非静态方法,因为实例化类了,但是一般不这么做)
因为static 是和类一起加载的,当类存在时,加static的方法也就存在了
没有加static的方法,需要 类实例化 之后,才能存在
*/
public static void a(){
System.out.println("静态方法a");
Student student = new Student();
student.read();//非静态方法
Student.say(); //静态方法
}
public void b(){
System.out.println("非静态方法b");
a();
Student.say();
}
}
6.2静态代码块 , 匿名代码块 ,无参构造
package com.wlw.oop.demo08;
public class Person {
// 第二个被执行
{
//代码块(匿名代码块)
//创建Person对象时,它自动就创建了,在构造器之前
//可以赋一些初始值
//程序在执行的时候,不会主动调用这个代码块
System.out.println("匿名代码块");
}
// 第一个被执行,但只执行一次
static {
//静态代码块 : 加载一些初始化的数据
//类一加载,它就执行了,永久执行一次
System.out.println("静态代码块");
}
//第三个被执行
public Person() {
System.out.println("无参构造器");
}
public static void main(String[] args) {
Person person1 = new Person();
System.out.println("=====================");
Person person2 = new Person();
}
}
/*
执行结果:
静态代码块
匿名代码块
无参构造器
=====================
匿名代码块
无参构造器
*/
6.3静态导入包
package com.wlw.oop.demo08;
//静态导入包
import static java.lang.Math.random;
import static java.lang.Math.PI;
public class Test {
public static void main(String[] args) {
System.out.println(Math.random()); //一般情况下
System.out.println(random());
System.out.println(Math.PI); //一般情况下
System.out.println(PI);
}
}