相信大家都会发现很多面向对象的编程语言中都有比较多的访问修饰符,拿Java来说,当我们在类作为模型创建对象之后可以访问对象拥有的属性或者方法。这些方法的使用却是大有区别。这里对常见的几种修饰符、重载重写的方法、静态成员的使用方法简单进行一下说明。
一、Java中的几种访问修饰符
Java作为一门优秀的面对对象编程语言,强大在于Java非常灵活、涵盖面广、可移植性高等等优点,这里对Java中的几种访问修饰符做一下说明。
public:
作为一种公有性质的访问修饰符,它的使用面非常广,在创建项目的时候我们可以发现,public访问修饰符在任意的位置都可以访问。
private:
作为一种私有属性的访问修饰符,它的使用面最窄,除了本类中可以进行访问之外都不能进行对于私有变量的修改或者是私有成员方法的使用。但是相对应的,该种访问修饰符的适用面越窄,它的安全性越高。
protected:
作为一种受保护的访问修饰符,它的使用面在public和private之间。使用的方法顾名思义,它在项目中的使用的时候除了在一个project下的同一个package以外的类和父类下的子类中都不能进行跨包访问。
默认:
很多情况下,程序员会提前想好需求再动手,不排除很多老手们想到哪里就写到哪里。默认形态下的访问修饰符就给了很大的空间。默认类型的访问修饰符只在当前的package下可以进行访问。
总结:
访问修饰符 | public | private | protected | 默认 |
---|---|---|---|---|
访问范围 | 任意位置 | 本类 | 在当前类、同包子类/非子类、跨包子类调用;跨包非子类不允许 | 允许在当前类、同包子类/非子类调用;跨包子类/非子类不允许调用 |
上面的总结想必已经言简意赅的说明了常用访问修饰符的访问方式。
这里我们用代码实验一下对于不同访问修饰符的使用场景。
People.java:
/* final class:该类没有子类 public final class \ final public class
* final 方法:该方法不允许被子类重写,但是可以正常被子类继承使用
* final 方法内局部变量:只要在具体被使用之前进行赋值即可,一旦赋值不允许被修改
* 类中成员属性:赋值过程:1、定义直接初始化 2、构造方法 3、构造代码块
*/
public class People{
/*
* 公有的访问修饰符:public
* 私有的访问修饰符:private
* 受保护的访问修饰符:protected
* 默认
*
* private:本类
* 默认:本类、同包
* protected:本类、同包、子类
* public:本类、同包、子类、其他
* 访问范围自上而下依次扩大,限制能力自下而上依次增强
*/
/*
* private:只允许在本类中进行访问
* public:允许在任意位置访问
* protected:允许在当前类、同包子类/非子类、跨包子类调用;跨包非子类不允许
* 默认:允许在当前类、同包子类/非子类调用;跨包子类/非子类不允许调用
*/
private String name = "妮妮";// 暱称
protected int month;// 年龄
String species = "中国人";// 人种
public final static int temp = 12;// 可在子类定义和父类重名的属性
static {
System.out.println("我是父类的静态代码块");
}
public static int st2 = 23;
private static int st1 = 22;
{
// temp=12;
System.out.println("我是父类的构造代码块");
}
// 父类的构造不允许被继承、不允许被重写,但是会影响子类对象的实例化
public Animal() {
month = 2;
// temp=20;
System.out.println("我是父类的无参构造方法");
}
public Animal(String name, int month) {
this.name = name;
this.month = month;
System.out.println("我是父类的带参构造方法");
}
public String getName() {
// this.temp=22;
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public String getSpecies() {
return species;
}
public void setSpecies(String species) {
this.species = species;
}
// 吃东西
public void eat() {
System.out.println(this.getName() + "在吃东西");
}
public void eat(String name) {
System.out.println(name + "在吃东西");
}
}
Boy.java:
/**
* 继承是一种类与类之间的关系
* 使用已经存在的类的定义作为基础建立新的类
* 新类的定义可以增加新的数据或者新的功能,也可以使用父类的功能,但不能选择性地继承父类
* 父类(基类) 子类(派生类) extends表示继承
* @author Administrator
*/
public class Boy extends People {
private double weight;// 体重
public int temp=300;
public static int st3 = 44;
static {
System.out.println("我是子类的静态代码块");
}
{
System.out.println("我是子类的构造代码块");
}
public Boy() {
// People temp=new Peole();
// private的属性不能在类外进行访问使用
// temp.name;
// public的属性可以允许在任意的位置访问
// this.temp=12;
// this.month=23;
// this.species="";
System.out.println("我是子类的无参构造方法");
}
public Boy(String name, int month) {
/*
* 子类构造默认调用父类无参构造方法 可以通过super()
* 调用父类允许被访问的其他构造方法 super()
* 必须放在子类构造方法有效代码第一行
*/
super(name, month); // this
System.out.println("我是子类的带参构造方法");
}
public static void say() {
// this.weight=20;
// super.name="aa";
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
// 跑动的方法
public void run() {
// super();
// eat();
// People();
System.out.println(this.getName() + "是一个" + this.getSpecies() + ",它在快乐的奔跑");
}
}
二、重写和重载的区别在哪里?
方法重载:
1、同一个类中
2、方法名相同,参数列表不同(参数顺序、个数、类型)
3、方法返回值、访问修饰符任意
4、与方法的参数名无关
方法重写:
1、有继承关系的子类中
2、方法名相同,参数列表相同(参数顺序、个数、类型)
3、方法返回值相同,访问修饰符,访问范围需要大于等于父类的访问范围
(如果在使用方法重写的时候用小于父类的访问范围,报错:不能降低父类当中的成员方法的可见性)
4、与方法的参数名无关
三、静态方法和非静态方法的执行顺序?在子类和父类中又有何区别?
静态方法和最终方法不能被重写;
但静态方法在子类中可以通过隐藏父类方法的方式重新实现。
重写方法的返回值应该与父类方法相同或者是父类方法返回值的子类; 重写方法访问权限必须大于等于父类方法。
先执行父类的静态成员再执行子类的静态成员; 初始化父类的属性再访问父类构造代码块之后访问父类无参构造方法;
最后依次初始化子类属性访问子类构造代码块,无参构造方法;
继承后的初始化顺序:
父类静态–子类静态–父类普通代码块–父类构造代码块–子类普通代码块–子类构造代码块