注:部分代码演示如果因长度问题观看不便利,可粘贴到idea中观看
一、构造方法
1、概念
(1)构造方法又叫构造器,构造函数单词constructor
(2)构造方法就是用来创建对象的
(3)每个类中都有构造方法,但是默认隐藏的
2、作用
(1)通过调用构造方法,可以在队中创建对象
(2)属性、方法初始化
3、无参构造
public 类名() { } 例如: public Person () {
} //无参构造 } public class Demo1 { public static void main(String[] args) { Person p1 = new Person();//创建对象 } } |
1、每个类都有一个默认的无参构造方法。 2、构造方法没有返回值,也不需要定义返回值类型,连void也没有。 3、构造方法的方法名只能是当前类类名。 4、只能通过new来调用。 |
4、有参构造
有参构造就是给构造方法设计参数,调用构造方法时传入参数给属性赋值。
public 类名(数据类型 变量名){ this,成员属性 = 变量; 例如 class Student { public Student(String name, int age) { this.name = name; this.age = age; } //有参构造 } public class Demo2 { public static void main(String[] args) { //对象的创建依赖构造方法出来的!!! Student stu = new Student("狗蛋", 12); } } |
1、一旦写了有参的构造方法,默认的无参构造方法就没了。 2、如果写了有参的构造方法但是没有传参会报错,想解决可以选择传参或者再写一个无参的放在那里。 |
- 重载
重载是指方法中的重载,作用是方便调用,根据自己传入的参数决定执行哪个方法
class Person{ String name;
public void play () { System.out.println("玩耍"); } public void play (String name) { System.out.println(name + "玩耍"); } /*public void play (String sb) { System.out.println(sb + "玩耍"); } //只是修改了变量名 } public class Demo1 { public static void main(String[] args) { Person p1 = new Person(); p1.play(); p1.play("狗蛋"); } } |
|
- 封装(困难,需要多加练习)
面向对象的三个基本特征:封装,继承,多态
1、封装是什么
封装就是打包,将代码封装起来,有方法的封装和类的封装。作用是隐藏一些真实的细节,用户只需要使用即可。
1、类的封装
完整的封装步骤:
- 属性私有化,在前面设置private修饰符
- 提供set/get方法
class Person { private String name; private int age; public void setName (String name) { this.name = name; } public String getName () { return this.name; } public void setAge (int age) { this.age = age; } public int getAge () { return this.age; } } public class Demo1 { public static void main(String[] args) { Person p1 = new Person(); p1.setName("张三");//赋值 p1.setAge(12); System.out.println(p1.getName());//取值 System.out.println(p1.getAge()); } } |
1、为属性添加private方法后,使用alt+insert选中set and get 选项就可以全选将set/get方法自动导出。 2、set方法是为了赋值的,get方法是为了取值的。赋值和取值时在mian函数中进行。 |
四、继承
1、继承的概念
继承的关键词为extends,构成继承关系后子类能使用父类中的属性和方法。
注意:java中继承是单继承,类只能继承一个类,就是只有一个父类。
public class 子类 extends 父类{ } |
2、为什么要继承
(1)减少代码
(2)是形成多态的前提
3、继承入门代码
public class Animal { int age; String name; void eat(){ System.out.println("吃" ); } } |
动物类为父类,里面有两个属性一个方法。 |
public class Dog extends Animal{// 继承 } |
狗类为子类 |
public class TestExtends{ public static void main(String[] args) { Dog dog = new Dog( );
dog.name = "大黄"; dog.eat(); |
Dog类继承Animal类,就可以父类属性和方法。 |
4、继承中的属性
(1)子类继承父类,就可以继承父类的属性。
(2)如果给父类设置私有属性,子类就无法使用父类的属性。
(3)假如子类和父类中有重名的属性,子类默认使用自己的(一般不会重复)。
5、继承中的方法
(1)继承中子类可以使用父类非私有方法。
(2)继承中,子类和父类中有一样的方法,默认调用自己的(即是重写)。
6、继承中的构造方法
(1)在创建子类对象时,会先创建父类对象再创建子类对象,因为子类构造方法里默认有super(); 也就是父类的无参构造方法并且在第一位。
五、重写
1、重写的概念
重写也可以叫做覆盖,它发生在继承中,子类重写父类的方法。当父类满足不了子类的需求了,子类才去重写父类的方法。
注意:重写只和方法有关
2、重写的特征
(1)访问修饰符一致
(2 )返回值类型一致
(3)方法名一致
(4)参数列表一致
总结:只有方法体的不同,其余一致。
3、重写入门代码
public class Father { public void eat () { System.out.println("吃窝窝头"); } } |
父类写了eat方法,方法体为吃窝窝头。 |
public class Son extends Father{ @Override public void eat() { System.out.println("吃白面馒头"); } } |
子类重写了父类的eat方法,将方法体改为了吃白面馒头。 @Override只是告知程序员 这个方法 是重写的而已,是重写的严格限定。 |
public class Demo1 { public static void main(String[] args) { Son son = new Son(); son.eat(); } } |
结果为打印“吃白面馒头”。 |
六、this和super
1、概念
this |
super | |
作用 |
指代当前对象 |
指代父类对象 |
调用属性时 |
this.属性(自身属性) |
super.属性(父类属性) |
调用方法 |
this.方法(自身方法) |
super.方法(父类方法) |
调用构造方法 |
this()调用自身构造方法 |
super()调用父类·构造方法 |
使用位置 |
构造方法或者方法中 |
2、入门代码
public class Dog extends Animal{ String name = "二哈"; // 无参构造 public Dog(){ System.out.println("Dog()" ); } @Override void eat() { System.out.println("狗吃骨头" ); } public void show() { // 调用自己属性name System.out.println(this.name ); // 调用父类属性name System.out.println(super.name ); this.eat();//调用自己/父类方法 super.eat();//调用父类方法 } } |
七、访问权限修饰符
当前类中 |
同包不同类中 |
不同包但是是子类 |
不同包且不是子类 | |
public |
√ |
√ |
√ |
√ |
protected |
√ |
√ |
√ | |
默认 |
√ |
√ | ||
private |
√ |
八、final
1、概念
final是一个修饰符,用来修饰类,属性和方法的。意思:最终的。
2、特点
(1)修饰类时,例如final class,类就不能再被继承,等于这个类绝后了。
(2)修饰变量(属性)时,例如final int a, 变量就成了常量需要立刻赋上初始值并且不能再修改。
(3)修饰方法时,方法不能被重写
(4)修饰对象的引用时,内存地址无法被修改
3、final入门代码
//1.使用final修饰的类无法被继承 //final class Person { class Person { String name; //2.修饰属性(成员变量) 一定先赋值,一旦赋值无法更改 final int age = 18; public void eat () { //3.修饰局部变量 变量可以先不赋值,但是使用的是否必须赋值,且赋完值以后无法修改 final int a = 19; // a = 23;//会报错 System.out.println(a); } //4.修饰方法, final修饰的方法不能被重写 public final void sleep () { System.out.println("睡觉"); } } class Man extends Person { /*public final void sleep () { System.out.println("睡觉"); }*/ //报错 } public class Demo1 { public static void main(String[] args) { //5.final修饰对象的引用 final Person p1 = new Person(); //p1.age = 23; System.out.println(p1);//1b6d3586 Person p2 = new Person(); System.out.println(p2);//4554617c //p1 = p2; 报错!!! System.out.println(p1);//4554617c } } |
九、static
1、概念
static的意思是静态的,是一修饰符。static修饰的属性和方法不在堆里,而是在方法区里且在内存只有一个,不管创建多少对象,该类静态属性和方法也只有一个,被该类的所有对象共享。
2、加载时机
随着类的加载而加载,在栈和堆没出现之前就已经加载了并且在加载时就行了初始化。
3、注意事项
static修饰的方法里不能使用this,因为你不可能指望一辆公交车只属于你一个人。
4、static入门代码
class Person{
|
5、总结
(1)static修饰属性时调用: 类.静态属性
(2)static修饰方法时调用: 类.静态方法
(3)static修饰代码块 :只要类加载(new的时候)就会执行静态代码块。 执行顺序:静态代码块》代码块》构造方法
6、使用场景
(1)场景1:当想要某个数据被对象共享时,就定义该属性为static,例如多个窗口对象共享火车票数据。
class TikectCounter { static int tikect = 100; public void sub () { tikect--; } } public class Demo5 { public static void main(String[] args) { TikectCounter tikectCounter1 = new TikectCounter(); //每调用一次sub()方法就会让公共的票-1 tikectCounter1.sub(); System.out.println(tikectCounter1.tikect); TikectCounter tikectCounter2 = new TikectCounter(); tikectCounter2.sub(); System.out.println(tikectCounter2.tikect); TikectCounter tikectCounter3 = new TikectCounter(); tikectCounter3.sub(); System.out.println(tikectCounter3.tikect); } } |
十、多态
1、概念
多态,就是指方法的多种状态,换句话说多态就是同一个方法会表现出不同的状态。
2、多态的前提
(1)继承/实现(有父类子类关系)
(2)重写
(3)父类引用指向子类对象(向上转型)
3、多态入门例子
public class Animal { public void eat(){ System.out.println("动物吃" ); } } |
public class Dog extends Animal {// 多态条件1继承 // 多态条件2重写 @Override public void eat() { System.out.println("狗吃骨头" ); } } |
public class TestPoly { public static void main(String[] args) { // 父类引用指向父类对象 // Animal animal = new Animal(); // 父类引用指向子类对象 Animal animal = new Dog(); animal.eat();// 编译看父类,运行看子类 // eat方法是子类在执行 } } |
4、多态的作用
减少耦合,提供扩展性
(1)现在有需求,设计方法传入一个狗类,执行出“狗吃骨头”。
(2)现在需求变了,想要表现出猫如何吃东西,该怎么办?
(3)假如,要展现动物园所有动物如何吃呢? 再假如后续又来了以前没有的动物,该如何表现吃的行为呢? 简单粗暴的想法,多定义几个方法..... 可以,但是很麻烦! 这些写,扩展性不好,来一个需要都需要改代码....
怎么办? 就需要多态!
只需要将方法的参数列表改变成父类即可,调用时传入想要表现的子类对象即可
5、多态使用注意事项
(1)父类里面的方法子类没有重写的话,无法体现多态。
(2)子类里面有特有方法,向上转型后父类方法也无法调用。
class Super { |
十一、向上&向下转型
1、向上转型
父类引用指向子类对象Animal animal = new Dog();
将Dog类(子类)的对象包装的成Animal类(父类)。
向上转型后的注意事项:
(1)父类引用只能调用父类中有的方法(编译看父类)。
(2)真正执行看子类。
2、向下转型
向上转型是子类对象变父类对象,向下转型就是父类对象变子类对象,类似于Dog dog = (Dog) Animal();
向下转型想要成功,需要先向上转型再向下转型。成功以后就可以让父类对象变成子类对象来调用子类的方法。
向下转型例子
class Person { public void feed (Animal animal) {//在喂的方法中 去调用狗的看门方法 咋办? //即调用eat方法又调用lookdoor方法,要求上面的feed的参数必须Animal animal.eat(); //animal 父类的引用。 只需要向下转型即可!!! Dog dog = (Dog) animal; //在mian函数里向上转型过了,所以只需要一个向下转型 dog.lookDoor(); } } class Animal { public void eat () { } } class Dog extends Animal{ @Override public void eat() { System.out.println("狗吃剩饭"); } public void lookDoor () { System.out.println("狗能看家!!!"); } //这个方法是狗类独有的,Animal类就可以通过向下转型调用 } class Cat extends Animal { @Override public void eat() { System.out.println("猫吃老鼠"); } } public class Demo1 { public static void main(String[] args) { Dog dog1 = new Dog(); Person p1 = new Person(); p1.feed(dog1); //子类给父类赋值等同于向上转型 } } |
3、instanceof
语法格式 boolean 变量 = 对象 instanceof 类;
作用是测试左边的对象是否是右边类的实例。左边的对象是右边类或者子类创建的对象的时候返回true反之false。
举例:
class Animal {} class Dog extends Animal {} class Cat extends Animal{} public class Demo1 { public static void main(String[] args) { Animal animal = new Animal(); Dog dog = new Dog(); Cat cat = new Cat(); System.out.println(animal instanceof Animal); //true System.out.println(dog instanceof Animal); //true System.out.println(animal instanceof Dog);//false //规律: instanceof的左边的辈分比右边小 或者同类的平辈。才能是true //System.out.println(dog instanceof Cat);//false //开发中用的!!! Animal animal1 = new Dog();//向上转型 System.out.println(animal1 instanceof Dog);//true } } |
拓展:
class Person { public void feed (Animal animal) { //在喂的方法中 去调用狗的看门方法 咋办? //即调用eat方法又调用lookdoor方法,要求上面的feed的参数必须Animal animal.eat(); //animal 父类的引用。 只需要向下转型即可!!! if (animal instanceof Dog) { Dog dog = (Dog) animal;// { //防止因为new Dog以外的导致报错,就利用instanceof只让类是Dog的运行 dog.lookDoor(); } if (animal instanceof Cat) { Cat cat = (Cat) animal; cat.sleep(); } } } class Animal { public void eat () { } } class Dog extends Animal{ @Override public void eat() { System.out.println("狗吃剩饭"); } public void lookDoor () { System.out.println("狗能看家!!!"); } } class Cat extends Animal { @Override public void eat() { System.out.println("猫吃老鼠"); } public void sleep () { System.out.println("猫看电视!!!"); } } public class Demo1 { public static void main(String[] args) { Dog dog1 = new Dog(); Person p1 = new Person(); p1.feed(dog1);// p1.feed(new Cat());//传参数传的是个cat } } |
十二、多态的应用场景
1、方法参数列表是父类类型,调用方法传参数时,传入子类对象,运行时出现各自子类效果
2、方法返回值是父类类型
3、数组类型是父类类型,数组的真实的值是子类对象
十三、toString 方法
转变为字符串方法,idea插件中的tpg再导入javabean时会自动填上
class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = 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; } @Override// 重写的方法 生成即可 public String toString() { return "{" + "名字='" + name + '\'' + ", 年龄=" + age + '}'; } } public class Demo1 { public static void main(String[] args) { Person p1 = new Person("张三", 23); System.out.println(p1);//com.qf.h_toString.Person@1b6d3586 //内存地址对程序员是不友好的, 看不懂数据 //重写toString以后,咱们的对象变得容易让人阅读 } } |