面向对象语言的三大特征:
封装:
1.封装含义:
- 包装,将一些常用功能进行抽取,定义成一个方法;
- 隐藏,面向对象特征中的封装,对类中的成员对外是否可见进行控制(使用权限修饰符控制成员对外可见性进行控制)
2.封装案例:
- 将类中属性私有化。提供公共权限的构造方法,外界可以通过公共构造方法对私有成员进行赋值,但是不能获取私有成员的值。
import java.util.Scanner;
public class pack {
private String name;//私有化name的权限。
private int num;//私有权限外界可以通过公共构造方法对其赋值,但是无法直接获取,必须通过其他的公共构造方法对其进行获取。
public void setName(String name) {
this.name = name;
}//使用构造方法对name进行赋值
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}//使用构造方法获取name。
}
class test1{
public static void main(String[] args) {
pack p=new pack();
Scanner scanf=new Scanner(System.in);
System.out.println("输入姓名:");
String n= scanf.next();
System.out.println("输入号码:");
int m= scanf.nextInt();
p.setName(n);
p.setNum(m);
System.out.println(p.getName());
System.out.println(p.getNum());
}
}
2.将某些方法私有化。
3.java设计模式
解决一类问题的固定方式
- 单例模式:单个实例,在系统中,想让某个类只能创建一个对象。
public class singleExample {
static singleExample single=null;
private singleExample(){
}//将构造方法私有化,外界就无法使用构造方法,无法创建新对象
public static singleExample getsingExample(){
int i=0;
if (single==null){
i++;
single=new singleExample();
System.out.println(i);
}
return single;
}
}//单例模式,使用这个方法可以使其只创建一次对象。
class singleTest{
public static void main(String[] args) {
singleExample.getsingExample();
System.out.println(""+singleExample.getsingExample());
}
}
继承:
子类继承父类:
- 子类可以拥有父类的功能;
将共性属性和行为进行抽取,这样就不需要在每个类中定义同样属性和行为,只需类与类之间建立继承关系即可。
优点:
- 减少代码的冗余,提高代码的复用性;
- 提高程序的扩展性;
- 继承的出现让类与类之间产生了is-a的关系,为多态的使用提供了前提。
语法:
需要关键词extends
class animal{
}
calss dog extends animal{
}
继承的细节:
-
子类会继承父类所有的实例变量和实例方法;
-
子类不能直接访问父类中私有的(private)的成员变量和方法;
-
java只支持单继承,不支持多个继承,但是支持多重继承。
class animal{ } calss dogs extends animal{ } class localdog extends dogs{ }
-
java中一个类没有extends关键字显示的继承其他类,那么这个类默认自Object类,Object是java中最顶级的类。
方法的重写(Override):
- 有时候,父类方法中的实现(父类方法中为完成功能所写的代码),不能满足子类中需要(与子类实现不同)就可以将父类中方法在子类中进行重写(在子类中对父类中某个方法进行重写)。
- 注意:构造方法、静态方法不能重写,成员变量不存在重写。
方法重写的规则:
-
子类重写的方法必须和父类被重写的方法名称,参数列表相同。
-
子类重写的方法的返回值类型与父类保存一致。
-
子类重写的方法使用的访问权限不能小于父类被重写方法的访问权限。
注意:① 父类私有方法不能重写 ② 跨包的父类默认权限的方法也不能重写 -
子类方法抛出的异常不能大于父类被重写方法的异常
-
@Override//注解标记,表示此方法是从父类中重写来的。在编译期间会进行语法的检测 实例: public class AnimalCat extends Animal{ public void mouse(){ System.out.println(name+"抓老鼠"); } @Override public void setName(String name) { this.name="社会"+name; } }
super关键字
- 调用父类中定义的成员方法;
- 在子类构造器中调用父类的构造器;
- 访问父类中定义的属性。
注意:
-
当子父类出现同名成员时,可以用super表明调用的是父类中的成员;
-
super还可以追溯父类的父类;
-
super和this用法相像,this代表本类对象的引用,super代表父类的内存空间的标识。
-
不要把super误认为是父类对象,在创建子类对象时,不会创建父类对象,只会将父类中的信息加载到子类对象中存储。
-
super的用法:
- super.成员变量
- super.成员方法
- super()表示调用父类中的构造方法
//父类 public class Animal { String name; int age; public void start(){ name="tata"; age=12; } public void setAge(int age) { this.age = age; } }
//子类 public class AnimalCat extends Animal{ public void setDate() { super.start();//在构造方法的首行 }//super继承构造方法 }
继承中的构造方法:
- 子类继承父类时,不会继承父类的构造方法。只能通过“super(形参列表)”的方式调用父类指定的构造方法。
- 规定super(形参列表),必须声明在构造器的首行。
- 如果在子类构造器的首行没有显示调用super(形参列表),则子类此构造器默认调用super(),即调用父类中空参的构造器。
- 这么做是为了保证先对父类成员进行初始化。
抽象类:
被abstract修饰的类,里面可能会包含抽象方法。
注意:
- 抽象类除了不能创建对象之外其他功能都正常。
- 抽象类只能用作基类,表示的是一种继承关系。继承抽象类的非抽象类必须实现其中的所有抽象方法,而已实现方法的参数、返回值要和抽象类中的方法一样。否则,该类也必须声明为抽象类
public abstract class Animal {
private String name;
private int age;
public abstract void eat();//抽象方法
}//抽象类
抽象方法:
-
抽象方法是一种特殊的方法:他只有声明,而没有具体的实现。
-
抽象方法必须用abstract关键字进行修饰。
-
抽象方法:只有方法声明(定义public void test()),没有具体的实现。
-
可以在父类中只定义,在子类中重写实现。
-
静态方法不能修饰为抽象方法。
多态:
多种状态:
-
父类引用指向子类对象,从而产生多种形态
Animal dog=new Dog(); Animal cat=new Cat();
public abstract class Animalmain { public abstract void eat(); public abstract void feed(); } public class Cat extends Animalmain{ public void eat(){ System.out.println("猫吃鱼"); } public void feed() { System.out.println("fish"); } } public class Dog extends Animalmain{ public void eat(){ System.out.println("狗吃骨头"); } public void feed(){ System.out.println("bone"); } } public class Person { public void eat(Animalmain animalmain){ animalmain.eat(); } public void feed(Animalmain animalmain){ animalmain.feed(); } } public class test { public static void main(String[] args) { Animalmain dog=new Dog(); Animalmain cat=new Cat(); Person person=new Person(); cat.eat(); dog.eat(); person.feed(cat); person.feed(dog); } }
注意事项:
-
注意成员调用时,分为编译期间和运行期间;
- 编译期间:写代码时,由于类型上升为父类类型所以只能调用到父类中定义的成员方法;
Animal cat=new Cat(); cat.eat();//调用的是Animal里面的成员方法
- 运行期间:运行代码时实际调用的是子类中重写的方法。
- 总结:对非静态成员,编译看左边,运行看右边。
-
如果子类没有重写方法则直接调用父类中的方法。
-
对于静态的成员变量和方法而言编译看左边,运行也运行左边;
-
注意:
为了实现多态性,可以将子类类型向上转为父类类型,
但是一旦类型上升为父类类型,那么就调用不到子类中特有的方法。
这就是多态在某种情况下的缺点。
解决方法:
向下转型:
把父类类型转为子类类型。
Dog d=(Dog)dog;//强制转换为Dog类
public class Animalmain {
public void feedAnimal(Animalmain animalmain){
animalmain.eat();
if (animalmain instanceof Dog){//判断父类与子类是否是一个类型
Dog dog=(Dog)animalmain;//将animalmain强制转换为Dog然后将animalmain内的成员赋给dog;
dog.feed();//调用feed方法
}
}
}