类与对象

1.回顾方法

package com.lin.study.oop.demo01;

import java.io.IOException;

public class Demo01 {
   public static void main(String[] args) {

  }

       /*
           修饰符     返回值类型       方法名(...){
                   //方法体
                   return 返回值;
           }
        */

   //return : 结束方法,返回一个结果
   public String sayHello(){
       return "Hello world!";
  }
   public void print(){  //void表示没有返回值
       return;//只能返回空
  }
   public int max(int a,int b){
       return a > b ? a : b;
  }
   public void readFile(String file) throws IOException{

  }

}

2.类与对象的创建

知识小店: 面向对象的本质: 以类的方式组织代码,以对象的形式封装数据

package com.lin.study.oop.demo02;

public class Student {
   //属性: 字段
   public String name;//null
   public int age;   //0

   //方法
   public void study(){
       System.out.println(this.name + "在学习");
  }
}
/*
package com.lin.study.oop;

import com.lin.study.oop.demo02.Student;

public class Application {
   public static void main(String[] args) {
       */
/*//*
/类 : 抽象的
       //类实例化后会返回一个自己的对象
       //xiaoming对象,就是Student类的具体实例

       Student xiaoming = new Student();
       Student xh = new Student();

       xiaoming.name = "小明";
       xiaoming.age = 3;

       System.out.println(xiaoming.name);//小明
       System.out.println(xiaoming.age);//3

       xh.name = "小红";
       xh.study();//小红在学习*//*

   }
}
*/

3.构造器

package com.lin.study.oop.demo02;

public class Person {
   //一个类中即使什么都没写,它也会存在一个空构造方法

   public String name;

   //构造器用于实例化初始值。
   //使用new关键字,其本质是在调用构造器。

   //1.一个无参数的构造器
   public Person(){
       this.name = "狂神";
  }

   //2.一个有参数的构造器
   //一旦定义了有参数的构造器,还想使用无参构造,就必须显式的定义一个无参构造
   public Person(String name){
       this.name = name;
  }
   
   //Alt + insert : 快捷生成构造器
}
/*
package com.lin.study.oop;

       import com.lin.study.oop.demo02.Person;

public class Application {
   public static void main(String[] args) {
       //new : 实例化了一个对象
       Person p = new Person();
       System.out.println(p.name);//狂神

       Person p2 = new Person("狂神2");
       System.out.println(p2.name);//狂神2
   }
}
*/

构造器总结:

  1. 和类名相同

  2. 没有返回值

作用:

  1. new 的本质是在调用方法

  2. 初始化对象的值

注意点:一旦定义了有参数的构造器,还想使用无参构造,就必须显式的定义一个无参构造

//Alt + insert : 快捷生成构造器

package com.lin.study.oop.demo03;

public class Pet {
   public String name;
   public int age;
   
   public void shout(){
       System.out.println("叫了一声");
  }
}
/*package com.lin.study.oop;

       import com.lin.study.oop.demo03.Pet;

public class Application {
   public static void main(String[] args) {
       Pet dog = new Pet();//狗对象
       Pet cat = new Pet();//猫对象

       dog.name = "旺财";
       dog.age = 3;
       dog.shout();

       System.out.println(dog.name);
       System.out.println(dog.age);
   }
}*/

4.类与对象小结

1.类与对象

类是一个抽象的模板

对象是一个具体的实例

2.方法

定义 调用

3.对应的引用

引用类型: 对象是通过引用来操作的

4.属性: 字段 成员变量

默认初始化值

数字: 0 或 0.0

char: u0000

boolean: false

引用: null

5.对象的创建和使用

  • 必须使用new关键字创建对象:Person p = new Person();

  • 对象的属性: p.name

  • 对象的方法: p.sleep()

6.类

静态的属性<------->属性

动态的行为<------->方法

 

 

5.封装

程序设计追求: "高内聚,低耦合"

package com.lin.study.oop.demo04;

public class Student {
   //属性私有
   private String name;//名字
   private int id;//学号
   private char sex;//性别
   private int age;//年龄

   //提供一些可以操作这个属性的方法
   //提供一些public 的 get,set 方法
   //get: 获得数据
   public String getName(){ return this.name; }
   public void setName(String name){ this.name = name;}

   //快捷生成get,set方法 : Alt + insert

   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;
  }


   //get,set方法的好处 : 可以通过方法体对属性进行限制
   public int getAge(){ return age; }
   public void setAge(int age){
       if (age>120||age<0){//属性不合法
           this.age = 3;
      }else{
           this.age = age;
      }
  }
}
/*
package com.lin.study.oop;

       import com.lin.study.oop.demo04.Student;

public class Application {
   public static void main(String[] args) {
       Student s1 = new Student();
       s1.setName("林");
       System.out.println(s1.getName());//林

       s1.setAge(-1);//属性设置不合法
       System.out.println(s1.getAge());//3
   }
}
*/

封装的好处:

  1. 提高程序的安全性保护数据

  2. 隐藏代码的实现细节

  3. 统一接口

  4. 系统可维护性增加了

6.继承

1.简单概念

父类

package com.lin.study.oop.demo05;

public class Person {
   public int money = 10_0000_0000;

   public void say(){
       System.out.println("说了一句话!");
  }
}

子类

package com.lin.study.oop.demo05;

public class Student extends Person{
   //这里什么都没有写
   //只是继承了Person类
}

测试类

package com.lin.study.oop;

import com.lin.study.oop.demo05.Student;

public class Application {
   public static void main(String[] args) {
      Student s = new Student();

      s.say();//说了一句话
       System.out.println(s.money);//1000000000
  }
}

知识总结;

  1. Ctrl + H :查看继承关系

  2. 学生 is 人: 派生类,子类

  3. 子类继承了父类,就会拥有父类的全部方法。

  4. 在Java中,所有的类,都默认直接或间接的继承Object类

  5. 私有的东西无法被继承。

2.super详解

父类

package com.lin.study.oop.demo06;

public class Person {


//区块1
//构造方法
public Person() {
System.out.println("这里是Person父类的无参空构造!");
}


//区块2
//定义属性
protected String name = "尚学堂";


//区块3
public void print(){
System.out.println("这是父类的方法!");
}
}

子类

package com.lin.study.oop.demo06;

public class Student extends Person{


//区块1
//构造方法
public Student() {
//隐藏代码super: 调用了父类的无参空构造
//super();//这里会调用父类的无参空构造,这里不写super也会先调用父类的空构造
System.out.println("这里是Student子类的无参空构造!");
}


//区块2
//定义属性
private String name = "狂神";

public void test(String name){
System.out.println(name);//林
System.out.println(this.name);//狂神
System.out.println(super.name);//尚学堂
}


//区块3
@Override
public void print() {
System.out.println("这里是子类的方法!");
}

public void test2(){
//这两个此时调用的是相同的方法!
print();//这里是子类的方法!
this.print();//这里是子类的方法!

super.print();//这里是父类的方法!
}
}

测试类

package com.lin.study.oop;

import com.lin.study.oop.demo06.Student;

public class Application {
public static void main(String[] args) {

//区块1
Student s = new Student();

//区块2
s.test("林");

//区块3
s.test2();
}
}

知识总结:

super注意点:

  1. super 调用父类的构造方法,必须在构造方法的第一行!

  2. super 只能出现在子类的方法或构造方法中!

  3. super 和 this不能同时调用构造方法!

对比this关键字:

  1. 代表的对象不同

    • this: 调用本身这个对象

    • super: 代表父类对象的引用

  2. 前提:

    • this: 没有继承也可以使用

    • super: 只能在继承条件下使用

  3. 构造方法:

    • this() : 调用本类的空构造器

    • super() : 调用父类的空构造器

3.方法重写

父类

package com.lin.study.oop.demo07;

public class B {

//静态方法
public static void test(){
System.out.println("B的静态方法!");
}

public void test2(){
System.out.println("B的非静态方法!");
}
}

子类

package com.lin.study.oop.demo07;

public class A extends B{

//静态方法
public static void test(){
System.out.println("A的静态方法!");
}

@Override
public void test2() {
System.out.println("A的非静态方法!");
}
}

测试类

package com.lin.study.oop;

import com.lin.study.oop.demo07.A;
import com.lin.study.oop.demo07.B;

public class Application {
public static void main(String[] args) {
//方法的调用
A a = new A();
a.test();//A的静态方法!
a.test2();//A的非静态方法!

B b = new A();
b.test();//B的静态方法!
b.test2();//A的非静态方法!
}
}

知识总结:

  1. 静态方法和非静态方法区别很大!

    • 静态方法: 方法的调用之和左边的数据类型有关。

    • 非静态方法: 重写

  2. 重写: 需要有继承关系,子类重写父类的方法!

    • 方法名必须相同

    • 参数列表必须相同

    • 修饰符: 范围可以扩大但不能缩小: public > protected > default > private

    • 抛出的异常: 范围可以被缩小,但不能被扩大!

  3. 重写中子类的方法和父类的方法必须一致,方法体不同

  4. 为什么需要重写:

    • 父类方法的功能,子类不一定需要,或者不一定满足!

    • Alt + Insert : override : 重写快捷键。

7.多态

父类Person

package com.lin.study.oop.demo07;

public class Person {

//父类中的一个方法
public void run(){
System.out.println("父类的run方法!");
}

public void sleep(){
System.out.println("这是父类特有的方法!");
}
}

子类Student

package com.lin.study.oop.demo07;

public class Student extends Person{

//在子类中重写run方法
@Override
public void run() {
System.out.println("在子类中重写的run方法!");
}

//定义一个子类特有的方法
public void eat(){
System.out.println("这是子类特有的eat方法!");
}
}

测试类Application

package com.lin.study.oop;

import com.lin.study.oop.demo07.Person;
import com.lin.study.oop.demo07.Student;

public class Application {
public static void main(String[] args) {
//一个对象的实际类型是确定的
//eg: new Student(); new Person();

//而可以指向的引用类型就不是确定的了
//父类的引用指向子类

//Student子类,能调用的都是自己的,或者继承父类的
Student s1 = new Student();
//Person父类型 可以指向父类,但不能调用子类中独有的方法
Person s2 = new Student();
Object s3 = new Student();

//1.父类中的run方法,并且子类进行了重写
s1.run();//输出: 在子类中重写的run方法!
s2.run();//输出: 在子类中重写的run方法!(子类重写了父类的方法,则执行子类重写后的方法)

//2.调用子类中特有的eat方法
s1.eat();//输出: 这是子类特有的eat方法!
//s2.eat();//错误!这里无法调用!
((Student)s2).eat();//将s2强制向下转换为Student类型,才可以调用子类中特有的eat方法

//3.父类中的sleep,且子类未重写
s1.sleep();//输出: 这是父类特有的方法!(子类可以正常调用)
s2.sleep();//输出: 这是父类特有的方法!(父类可以正常调用)
}
}

多态知识总结:

  1. 多态是方法的多态,属性没有多态。

  2. 对象能执行哪些方法,主要看对象左边的类型,和右边关系不大。

  3. 存在条件: 有继承关系,方法需要重写,父类引用指向子类对象。

    Father f1 = new Son();

  4. 无法重写的方法

    • static方法,它属于类,不属于实例。

    • final 常量修饰符修饰的方法。

    • private 修饰的方法。

8. instanceof 关键字

        //instanceof 关键字: 检查一个对象是否由指定类定义
//Object > String
//Object > Person > Teacher
//Object > Person > Student
Object o = new Student();
System.out.println(o instanceof Student);//T
System.out.println(o instanceof Person);//T
System.out.println(o instanceof Object);//T
System.out.println(o instanceof Teacher);//F
System.out.println(o instanceof String);//F


Person p = new Student();
System.out.println(p instanceof Student);//T
System.out.println(p instanceof Person);//T
System.out.println(p instanceof Object);//T
System.out.println(p instanceof Teacher);//F
System.out.println(p instanceof String);//编译出错!


Student s = new Student();
System.out.println(s instanceof Student);//T
System.out.println(s instanceof Person);//T
System.out.println(s instanceof Object);//T
System.out.println(s instanceof Teacher);//编译出错!
System.out.println(s instanceof String);//编译出错!

9.引用类型转换

父类Person

package com.lin.study.oop.demo07;

public class Person {

//父类中的一个方法
public void run(){
System.out.println("父类的run方法!");
}
}

子类Student

package com.lin.study.oop.demo07;

public class Student extends Person{

//定义一个子类特有的方法
public void eat(){
System.out.println("这是子类特有的eat方法!");
}
}

测试类Application

package com.lin.study.oop;

import com.lin.study.oop.demo07.Person;
import com.lin.study.oop.demo07.Student;

public class Application {
public static void main(String[] args) {
//引用类型之间的转换: 父类和子类

//1.由高到低转: 强制转换
Person obj = new Student();
//只有将对象obj转换为Student类型,对象obj才可以调用子类的eat方法
Student s = (Student)obj;
s.eat();//这是子类特有的eat方法!
//两句代码合成一句
//((Student)obj).eat();//这是子类特有的eat方法!

//2.由低到高: 自动实现
Student s2 = new Student();
s2.eat();//此时未转换

Person p = s2;//自动将s2转换为高类型Person
((Student)p).eat();//此时强制再转换回去才可以调用eat方法
}
}
  1. 子类转换为父类: 向上转型 : 自动实现

  2. 父类转换为子类: 向下转型 : 强制转换

10. static 关键字

package com.lin.study.oop.demo07;

public class Student {

//1.属性
private static int age;//静态的变量
private double score;//非静态的变量

//2.方法
public static void go(){}//静态方法
public void run(){}//非静态方法


public static void main(String[] args) {

//1.属性
Student s1 = new Student();
//静态的变量可以直接通过 类名.变量名 调用
System.out.println(Student.age);
//System.out.println(Student.score);//非静态的变量不可以这样调用

System.out.println(s1.age);
System.out.println(s1.score);

//2.方法
go();//正确: 静态方法可以调用静态方法
//run();//错误: 静态方法不可以调用非静态方法
}
}
package com.lin.study.oop.demo07;

public class Person {
public Person(){
System.out.println("构造方法");
}
{
System.out.println("匿名代码块");
}
static {
System.out.println("静态代码块");
}

public static void main(String[] args) {
Person p = new Person();
//执行顺序: 静态 > 匿名 > 构造
//静态static 只会执行一次
}
}

11. 抽象类

父类 : Action

package com.lin.study.oop.demo08;


//abstract 抽象类 : extends : 单继承
public abstract class Action {

//abstract 抽象方法 只有方法名字,没有方法实现!
public abstract void doSomething();
}

子类 : A

package com.lin.study.oop.demo08;

public class A extends Action {

//子类继承了抽象类,就要重写它的所有方法,除非子类也是抽象类
@Override
public void doSomething() {

}
}

抽象类总结 :

  1. 不能new这个抽象类,只能靠子类去实现它 : 约束!

  2. 抽象类也可以写普通的方法。

  3. 但抽象方法必须存在于抽象类中。

12. 接口

接口1 : UserService

package com.lin.study.oop.demo09;

//interface 定义接口的关键字,接口都需要有实现类。
public interface UserService {
//1.接口中的常量,默认为由 public static final 修饰
int AGE = 99;

//2.接口中的方法,默认为由 public abstract 修饰
void add(String name);
void delete(String name);
void update(String name);
void query(String name);
}

接口2 : TimeService

package com.lin.study.oop.demo09;

public interface TimeService {
void time();
}

实现类 : UserServiceImpl

package com.lin.study.oop.demo09;

public class UserServiceImpl implements UserService,TimeService{

//TimeService中的方法
@Override
public void time() {

}

//UserService中的方法
@Override
public void add(String name) {

}

@Override
public void delete(String name) {

}

@Override
public void update(String name) {

}

@Override
public void query(String name) {

}
}

接口知识总结:

  1. 类可以实现接口: implements 接口

  2. 实现了接口的类,就需要重写接口中的方法。

  3. 利用接口可以实现 伪多继承(多实现)。

  4. 接口不能被new实例化,接口中没有构造方法。

  5. implements 可以实现多个接口。

13. 内部类

成员内部类

package com.lin.study.oop.demo10;

public class Outer {

private int id = 10;
public void out(){
System.out.println("这是外部类的方法!");
}

public class Inner{
public void in(){
System.out.println("这是内部类的方法!");
}

//成员内部类可以获得外部类的私有属性
public void getID(){
System.out.println(id);
}
}
}

测试类

package com.lin.study.oop;

import com.lin.study.oop.demo10.Outer;

public class Application {
public static void main(String[] args) {
Outer o = new Outer();

//通过这个外部类的实例来实例化内部类
Outer.Inner i = o.new Inner();
i.in();//这是内部类的方法!
i.getID();//10
}
}