目录
六、权限修饰符:public、proctect、default、private
一、类的定义
public class ClassDemo{
//1.成员变量
String name = "张三";
int age = 18;
//2.成员方法
public void eat(){
System.out.println("吃饭");
}
}
二、类的使用
public class ClassTest {
public static void main(String[] args) {
//创建该类对象
ClassDemo a = new ClassDemo();
//打印该类成员变量
System.out.println(a.name);
System.out.println(a.age);
//调用该类成员方法
a.eat();
}
}
三、成员变量和局部变量的区别
1.定义位置不同.
- 成员变量: 定义在类中, 方法外。
- 局部变量: 定义在方法中, 或者方法声明上。
2.在内存中的存储位置不同
- 成员变量: 存储在堆内存。
- 局部变量: 存储在栈内存。
3.生命周期不同
- 成员变量: 对象的创建则存在
- 局部变量:方法的调用则存在
4.初始化值不同
- 成员变量: 有默认值
- 局部变量: 没有默认值, 须定义, 赋值, 才能使用
四、构造函数与关键字this
功能:类中创建构造函数可以使创建对象时给对象成员变量赋值
构造方法名必须和类名完全一致.
构造方法没有返回值, 不能出现void.
this:代表本类当前对象的引用
//类的定义
public class Cs{
int i;
//创建对象没有赋值时调用
public Cs(){};
//创建对象赋值时调用
public Cs(int i){
this.i = i;
}
}
//测试
public class Test{
public static void main(String[] args){
Cs cs = new Cs(1);
System.out.println(cs.i);
}
}
五、继承
意义:多个类中存在相同属性和行为时, 将这些内容抽取到单独的一个类中, 那么这些类就无需再定义这些属性和行为, 只要继承那个类即可。
好处:
1.提高了代码复用性
2.提高了代码可维护性
3.多态的基础.
坏处:
让类与类之间产生了关系, 也就让类的耦合性增强了.
开发原则: 高内聚, 低耦合。
- 内聚: 指的是类自己独立完成某些事情的能力.
- 耦合: 指的是类与类之间的关系.
public class Father{
int i=15;
public void eat(){
System.out.println("eating");
}
}
public class Son extends Father{
}
public class Test{
public static void main(String[] args){
Son son = new Son();
System.out.println(son.i);
son.run();
}
}
六、权限修饰符:public、proctect、default、private
权限修饰符是用来修饰类, 成员变量, 构造方法, 成员方法的
对应访问(包括继承与调用)权限 public protect default(默认) private 同一个类
1 1 1 1 同一个包中的子类或者其他类
1 1 1 0 不同包中的子类
1 1 0 0 不同包中的其他类(无关类包括本类)
1 0 0 0
public和default可以对类进行修饰,其他不行。
只展示了private对成员变量和成员方法的修饰,其他的权限修饰符可以自行测试 。
//定义私有变量
public class ClassDemo{
//1.私有成员变量
private String name = "张三";
private int age = 18;
//2.私有成员方法
private void eat(){
System.out.println("吃饭");
}
//通过共有成员方法设置或调用私有成员变量和私有成员方法
public String getName(){
return name;
}
public int getAge(){
return age;
}
public void useFunc(){
this.eat();
}
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age
}
}
//调用私有变量
public class ClassTest {
public static void main(String[] args) {
//定义对象
ClassDemo element = new ClassDemo();
//返回私有成员与调用方法
System.out.println(element.getName());
System.out.println(element.getAge());
element.useFunc();
//私有成员赋值
element.setName("李四");
element.setAge(15);
}
}
七、实际开发类一般格式
public class 类名{
//属性(成员变量), 全部用private修饰.
//构造方法, 一般提供两个(无参, 全参)
//getXxx()和setXxx()方法
//行为(成员方法), 根据需求来定义.
}
八、super
super:代表当前对象的父类的内存空间标识
可用于继承构造函数
public class Father{
int i;
public Father(int i){
this.i = i;
}
public void eat(){
System.out.println("eating");
}
}
public class Son extends Father{
//继承构造函数
public Son(int i){
super(i);
}
public func(){
System.out.println(super.i);
super.eat();
}
}
public class Test{
public static void main(String[] args){
Son son = new Son();
son.func();
}
}
九、方法重写
方法重写:子类中出现和父类一样的方法。
注意事项:
1.子类重写父类方法时, 方法声明上要用@Override注解来修饰.
2.父类中私有的方法不会被子类继承,更谈不上重写
3.方法重写要求返回值的数据类型也必须一样.
//定义父类
public class Father {
public void eat(String string){
System.out.println("father eat " + string);
}
}
//定义子类
public class Son extends Father{
@Override //修饰重写方法
public void eat(String string){
System.out.println("son eat " + string);
}
}
//测试
public class Test
{
public static void main(String[] args) {
Son son = new Son();
son.eat("fruit");
}
}
十、多态
在不用多态的前提下,会出现以下的情况
//子类1
public class Son1{
String name = "王七";
public void eat(){
System.out.println("Son1 eat");
}
}
//子类2
public class Son2 {
String name = "王八";
public void eat(){
System.out.println("Son2 eat");
}
}
//测试
public class Test {
public static void main(String[] args) {
Son1 son1 = new Son1();
Son2 son2 = new Son2();
//如果有更多的类
// Son3 son3 = new Son3();
// Son4 son4 = new Son4();
//.........
func1(son1);
func2(son2);
}
public static void func1(Son1 son1){
System.out.println(son1.name);
}
public static void func2(Son2 son2){
System.out.println(son2.name);
}
//则需要多写更多的函数
/* public static void func1(Son2 son2){
System.out.println(son1.name);
}
public static void func1(Son2 son2){
System.out.println(son1.name);
}*/
//对于同样功能的函数,因为输入对象类型不同,导致需要多很多相似的函数,会导致代码冗余
//而且会难以维护
}
这时候需要多态的使用
多态的基础:
1.继承关系
2.方法重写
3.父类引用指向子类对象( 即Father son = new Son(); )
1.成员变量:编译看声明类型(即Father), 运行也看声明类型。
编译时如果父类不存在该成员变量则会报错,输出也为父类成员变量的值。
2.成员方法:编译看声明类型, 运行看对象类型(即Son)。
编译时如果父类不存在该成员方法则会报错,输出优先调用的是子类的同名方法,若子类无该同名方法则调用父类的方法。
//定义父类
public class Father {
int age = 33;
String name = "王五";
public void eat(){
System.out.println("Father " + this.name + " eat");
}
}
//定义子类1
public class Son1 extends Father {
String name = "王八";
int age = 18;
int num = 1;
@Override
public void eat() {
System.out.println("Son1" + this.name + "eat");
}
public void study(){
System.out.println("study english");
}
}
//子类2
public class Son2 extends Father {
String name = "王八";
int age = 18;
int num = 2;
@Override
public void eat() {
System.out.println("Son2" + this.name + "eat");
}
public void study(){
System.out.println("study math");
}
}
//测试
public class Test {
public static void main(String[] args) {
Father son1 = new Son1();
Father son2 = new Son2();
//如果有更多的类
// Son3 son3 = new Son3();
//...
func(son1);
func(son2);
//func(son3);
//...
}
//只需要写一个函数就够了
public static void func(Father son){
System.out.println(son.name);//成员变量编译会看Father类是否存在,同时使用Father的age
son.eat(); //成员方法编译会看Son类是否存在,优先使用Son的eat()
//System.out.println(son.num); //无法使用子类独有变量
//son.study(); //无法使用子类独有方法
}
}
使用多态之后解决了上面的问题,但是又会发现一个问题。使用了多态但是子类的成员变量无法使用,并且子类自己本身含有但父类不存在的成员变量和成员方法无法使用。
我们通过向下转型来解决这个问题.
//测试
public class Test {
public static void main(String[] args) {
Father son1 = new Son1();
Father son2 = new Son2();
func(son1);
func(son2);
}
public static void func(Father son){
if (son instanceof Son1) {
Son1 sonNew = (Son1) son;
sonNew.study(); //可使用子类独有方法
}
else if(son instanceof Son2) {
Son2 sonNew = (Son2) son;
sonNew.study(); //可使用子类独有方法
}
}
}
十一、final、static关键字
final可以修饰类, 成员变量, 成员方法.
1. 修饰的类: 不能被继承>
2 .修饰的变量: 是一个常量, 只能被初始化赋值.
3. 修饰的方法: 不能被子类重写.
public final class Father(){} //不能被子类继承
final int NUM=16; //只能在定义变量是赋值,且无法改变值
public final void eat(){} //不能被重写
static可以修饰成员变量, 成员方法。
在创建对象前就已经随着类的加载而加载.
被static修饰的内容, 能被该类下所有的对象共享.
public class Student {
//成员变量
String name; //姓名
int age; //年龄
static int sum = 0; //创建了该对象的个数
public Student(){
sum += 1;
}
//成员方法
public static void show() {
System.out.println("static function");
}
}
//测试
public class Test(){
public static void main(String args){
Student.show();
Student student1 = new Student();
System.out.println(student1.sum);
Student student2 = new Student();
System.out.println(student2.sum);
}
}
十二、抽象类
没有方法体的方法定义为抽象方法,类有抽象方法, 该类必须定义为抽象类.
抽象类中可以有变量, 常量, 构造方法, 抽象方法和非抽象方法。
抽象类的特点:
1.必须用abstract关键字修饰,其抽象方法也需要用abstract修饰
2.抽象类中不一定有抽象方法, 有抽象方法的类一定是抽象类
3.抽象类不能实例化
4.如果子类是非抽象类, 必须重写父抽象类中所有抽象方法
5.如果子类是抽象类, 可以不用重写父抽象类中的抽象方法
抽象类的构造方法通过子类super()来实现赋值
//定义父类
public abstract class Father {
int age;
String name;
public Father(int age, String name) {
this.age = age;
this.name = name;
}
//抽象方法
public abstract void eat();
//抽象类中的非抽象方法
public void study(){
System.out.println("keep study");
}
}
//正常子类
public class Son1 extends Father {
int num;
//抽象类的构造函数赋值
public Son1(int age, int num,String name) {
super(age, name);
this.num = num;
}
//抽象方法重写
@Override
public void eat() {
System.out.println("Son1" + this.name + "eat");
}
public void print(){
System.out.println(this.num);
}
}
//抽象子类
public abstract class Son2 extends Father {
int num;
public Son2(int age, String name) {
super(age, name);
}
}
//测试
public class Test {
public static void main(String[] args) {
Father son1 = new Son1(19,1,"王七");
func(son1);
}
public static void func(Father son){
Son1 sonNew = (Son1) son;
sonNew.eat(); //抽象类抽象方法重写调用
sonNew.study(); //抽象类非抽象方法调用
sonNew.print(); //非抽象类子类方法调用
}
}
十三、接口
类中的成员方法与成员变量在继承中是子类需要共有的,而当需要某些类拥有自己的特性时,可以使用接口。
特点:
1.接口用interface关键字修饰,类和接口之间是实现关系, 用implements关键字表示
2.接口不能实例化
3.通过多态的方式, 创建其子类对象完成接口的实例化,即接口多态
4.子类是普通类, 必须重写父接口中所有的抽象方法
5.子类是抽象类, 可以不用重写父接口中的抽象方法
6.接口中是没有构造方法
接口中的成员变量与成员方法:
1.成员变量只能为常量,有默认修饰符: public static final
2.成员方法只能为抽象方法,有默认修饰符: public abstract
3.静态方法(JDK1.8后出现)
4.默认方法(JDK1.8后出现,必须用default修饰).
//定义父类
public abstract class Person {
int age;
String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
//抽象方法
public abstract void eat();
}
//接口
public interface Basketball {
int NUM=8; //是个常量,默认public static final修饰
void playBasketball(); //默认public abstract修饰
}
//子类
public class Teacher extends Person implements Basketball{
//抽象类的构造函数赋值
public Teacher(int age,String name) {
super(age, name);
}
//抽象方法重写
@Override
public void eat() {
System.out.println("Teacher" + this.name + "eat");
}
public void teach(){
System.out.println("teach student");
}
@Override
public void playBasketball() {
System.out.println("playing basketball");
}
}
//测试
public class Test {
public static void main(String[] args) {
Person son1 = new Teacher(19,"王七");
func(son1);
}
public static void func(Person son){
Teacher sonNew = (Teacher) son;
sonNew.eat(); //继承
sonNew.teach(); //该类共有
sonNew.playBasketball(); //接口实现
}
}
类与类: 继承关系, 单继承, 不能多继承,可以多层继承
类与接口: 实现关系, 单实现, 多实现,可以在继承一个类的同时实现多个接口
接口与接口: 继承关系, 单继承, 多继承