2-JAVA-面向对象编程基础

方法

(1)public和private
private修饰的属性只能在类内部调用,防止外部泄漏,可以采用类似的set方法赋值,因为set和get方法是public类型的,外部是可以访问的,同理private修饰的方法,也只限于类内部调用.
(2)this:只代表本类的成员变量,方法,构造方法.不代表一个方法中的局部变量,比如下面this.name 代表的是类Person中定义的成员变量name,不代表setName方法中传入的参数name

public class Main {
    public static void main(String[] args) {
        Person ming = new Person();
        ming.name = "Xiao Ming"; // 对字段name赋值
        ming.age = 12; // 对字段age赋值
    }
}
class Person {
    private String name;
    private int age;
//set方法
    public void setName(String name){
      this.name = name;
  }
  //get方法
  public String getName(){
  return this.name;
  }
}

(3)基本类型参数的传递,注意事项基本类型,是调用方值的复制。双方各自的后续修改,互不影响,下图代码中调用p.setAge(n),是将基础类型n的值复制出来一份,分配新的地址出来.所以后续修改n的值不会相互影响.

public class Main {
    public static void main(String[] args) {
        Person p = new Person();
        int n = 15; // n的值为15
        p.setAge(n); // 传入n的值
        System.out.println(p.getAge()); // 15
        n = 20; // n的值改为20
        System.out.println(p.getAge()); // 结果还是15
    }
}
class Person {
    private int age;
    public int getAge() {
        return this.age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

(4)引用类型参数的传递,调用方的变量,和接收方的参数变量,指向的是同一个对象。双方任意一方对这个对象的修改,都会影响对方(因为指向同一个对象嘛)

public class Main {
    public static void main(String[] args) {
        Person p = new Person();
        String[] fullname = new String[] { "A", "B" };
        p.setName(fullname); // 传入fullname数组
        System.out.println(p.getName()); // 输出A B
        fullname[0] ="D";
         System.out.println(p.getName()); // 输出D B
}
class Person {
    private String[] name;
    public String getName() {
        return this.name[0] + " " + this.name[1];
    }
    public void setName(String[] name) {
        this.name = name;
    }
}

(5)String也为引用类型,修改String类型的值,却没有相互影响

public class test {
	    public static void main(String[] args) {
	        Person p = new Person();
	        String str ="A";
	        p.setName(str); 
	        System.out.println(p.getName()); // 输出结果A
	        str = "B";
	        System.out.println(p.getName()); // 输出的结果依然是A,
	        /*
		因为 str = "B"; 这行代码只是改变了str变量的指向,
		由原来指向“A”改为指向“B”,但是“A”这个对象并没有改变,只有实例化的对象才会分配内存地址.所以Person p的name字段还是指向“A”的
		*/

	    }
	}
	class Person {
	    private String name;
	    public String getName() {
	        return this.name;
	    }
	    public void setName(String name) {
	        this.name = name;
	    }

}

构造方法

构造方法的参数没有限制,在方法内部,也可以编写任意语句。但是,和普通方法相比,构造方法没有返回值,我们都是用构造方法来New一个对象.
如果我们自定义了一个构造方法,那么,编译器就不再自动创建默认构造方法,默认的构造方法就没了.
既类里面的一个字段进行初始化,又在构造方法中对相同字段进行初始化,构造方法是后进行的.

class Person {
    private String name = "Unamed";//先进行初始化字段
    private int age = 10;
    //自定义构造方法Perison(String name, int age)
    public Person(String name, int age) {
        this.name = name;//再运行构造方法的赋值,最后name的值取得是构造方法的
        this.age = age;
    }
}

方法重载

是指多个方法的方法名相同,但各自的参数不同;
重载方法应该完成类似的功能,参考String的indexOf();
重载方法返回值类型应该相同
构造方法其实就是方法名必须是类名,传入参数不同.
方法的重载就是方法名相同,参数不同,不能和类名一样.

class Hello {
    public void hello() {
        System.out.println("Hello, world!");
    }
    public void hello(String name) {
        System.out.println("Hello, " + name + "!");
    }
    public void hello(String name, int age) {
        if (age < 18) {
            System.out.println("Hi, " + name + "!");
        } else {
            System.out.println("Hello, " + name + "!");
        }
    }
}

继承

	/*如果类没有extends的话,默认继承object类,所以下面的继承顺序是object -> Perison -> Student
	 * private定义父类,子类和外部都不能访问
	 * proteced外部不能访问,子类以及子类的子类可以访问
	 * super表示父类,在子类中利用super可以获取父类的属性和方法.
	 */
	public class JiCheng {
		public static void main(String[] args) {
			Student student = new Student();
			student.getSuperName("hello");
		}
	}
	//父类Person
	 class Person{
		private int sex;
		protected String name;
		protected Integer age;
		
		public String getName() {
			return name;
		}
		public void setName(String name) {
			this.name = name;
		}
		public Integer getAge() {
			return age;
		}
		public void setAge(Integer age) {
			this.age = age;
		}
	}
	//子类Student
	class Student extends Person{
		private int score;
		public int getScore() {
			return score;
		}
		public void setScore(int score) {
			this.score = score;
		}
		public void getSuperName(String name) {
			//此处如果写成this.name或者super.name,就代表是父类中的name了,就不是传入的参数name了
			super.setName(name);
			System.out.println(super.getName());
		}
	}

super深入了解,看下面例子,运行会报错

public class Main {
    public static void main(String[] args) {
        Student s = new Student("Xiao Ming", 12, 89);
    }
}
class Person {
    protected String name;
    protected int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
class Student extends Person {
    protected int score;
    public Student(String name, int age, int score) {
        this.score = score;
    }
}

这是因为在Java中,任何class的构造方法,第一行语句必须是调用父类的构造方法,如果我们没有明确地写调用父类的构造方法,编译器会帮我们自动加一句super();,所以,上例子Student类的构造方法实际上是这样:

class Student extends Person {
    protected int score;
    public Student(String name, int age, int score) {
        super(); //我们自己没有写父类的构造,系统就自动加上了
        this.score = score;
    }
}

但是上例子Person父类自定义了构造方法,所以我们在子类的构造方法中,要先初始化父类的构造方法,

class Student extends Person {
    protected int score;
    public Student(String name, int age, int score) {
        super(name, age); // 调用父类的构造方法Person(String, int)
        this.score = score;
    }
}

综上所述:Java只允许一个class继承自一个类,因此,一个类有且仅有一个父类。只有Object特殊,它没有父类,object是最高级别的父类,在我们没有写extends的时候,系统自动extends object类.super代表父类,每次new一个子类的构造方法时,都是先调用父类的构造方法.
把一个子类类型安全地变为父类类型的赋值,被称为向上转型,如下代码

Student s = new Student("Xiao Ming", 12, 89);
也可以写成
 Person s = new Student("Xiao Ming", 12, 89);

多态

在继承关系中,子类如果定义了一个与父类方法完全相同的方法,被称为覆写(Override),完全相同的方法指的是传入参数和返回类型都相同. 如下代码演示

class Person {
    public void run() {System.out.println("Person.run");}
}
class Student extends Person {
    // 不是Override,因为参数不同,这是子类中的一个新方法,成为Overload
    public void run(String s) {}
    //参入参数和返回值都相同,继承的子类中@Override可以省略,加上@Override可以帮助我们效验此方法是否在父类中存在.不存在会报错
    @Override
    public void run() { System.out.println("Student.run"); }
}

多态是指,针对某个类型的方法调用,其真正执行的方法取决于运行时期实际类型的方法,如下代码演示

Person p = new Student();
p.run(); // 输出结果:Student.run 调用的是Student里面的run方法

看下面代码它传入的参数类型是Person,我们是无法知道传入的参数实际类型究竟是Person,还是Student,还是Person的其他子类,因此,也无法确定调用的是不是Person类定义的run()方法。
所以,多态的特性就是,运行期才能动态决定调用的子类方法。对某个类型调用某个方法,执行的实际方法可能是某个子类的覆写方法。

public void runTwice(Person p) {
    p.run();
}

因为所有的class最终都继承自Object,其中toString是Object的方法,我们也可以覆用

 @Override
    public String toString() {
        return "Person:name=" + name;
    }

利用super可以在子类中调用父类的方法
如果一个父类不允许子类对它的某个方法进行覆写,可以把该方法标记为final。用final修饰的方法不能被Override

抽象类

如果一个class定义了方法,但没有具体执行代码,这个方法就是抽象方法,抽象方法用abstract修饰。因为无法执行抽象方法,因此这个类也必须申明为抽象类
使用abstract修饰的类就是抽象类。我们无法实例化一个抽象类
因为抽象类本身被设计成只能用于被继承,因此,抽象类可以强迫子类实现其定义的抽象方法,否则编译会报错。因此,抽象方法实际上相当于定义了“规范”。

面向抽象编程的本质就是:
1-上层代码只定义规范(例如:abstract class Person);
2-不需要子类就可以实现业务逻辑(正常编译);
3-具体的业务逻辑由不同的子类实现,调用者并不关心。

例如,Person类定义了抽象方法run(),那么,在实现子类Student的时候,就必须覆写run()方法:

public class Main {
    public static void main(String[] args) {
        Person p = new Student();
        p.run();
    }
}

abstract class Person {
    public abstract void run();
}

class Student extends Person {
    @Override
    public void run() {
        System.out.println("Student.run");
    }
}

接口

所谓interface,就是比抽象类还要抽象的纯抽象接口,因为它连字段都不能有.
一个类可以实现多个接口,接口也是数据类型,适用于向上转型和向下转型.
接口的所有方法都是抽象方法,接口不能定义实例字段.
接口可以定义default方法,实现类可以不必覆写default方法。default方法的目的是,当我们需要给接口新增一个方法时,会涉及到修改全部子类。如果新增的是default方法,那么子类就不必全部修改,只需要在需要覆写的地方去覆写新增方法.

public class Main {
    public static void main(String[] args) {
        Person p = new Student();
        p.run();
    }
}
interface Person {
   //非default方法
    void getName();
    //default方法,实现类Student可以不实现此方法
    default void run() {
        System.out.println("run");
    }
}
class Student implements Person {
   //实现类必须实现此方法
    public void getName() {
         System.out.println("name");
    }
}

静态字段和静态方法static

静态字段:无论修改哪个实例的静态字段,效果都是一样的:所有实例的静态字段都被修改了,原因是静态字段并不属于实例.
访问静态字段推荐 (类名.静态字段名)
静态方法:静态方法类似其它编程语言的函数,采用(类名.静态方法名)调用
因为静态方法属于class而不属于实例,因此,静态方法内部,无法访问this变量,也无法访问实例字段,它只能访问静态字段.
接口的静态字段:因为interface是一个纯抽象类,所以它不能定义实例字段。但是,interface是可以有静态字段的,并且静态字段必须为final类型

public interface Person {
   //因为interface的字段只能是public static final类型,所以我们可以把这些修饰符都去掉
    public static final int MALE = 1;
    public static final int FEMALE = 2;
}

Java内建的package机制是为了避免class命名冲突;
JDK的核心类使用java.lang包,编译器会自动导入;
JDK的其它常用类定义在java.util.,java.math.,java.text.*,……;
包名推荐使用倒置的域名,例如org.apache。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值