封装
一、概念
封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部分包装、隐藏起来的方法。封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。要访问该类的代码和数据,必须通过严格的接口控制。封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性。
二、实现JAVA封装的步骤
1、修改属性的可见性来限制对属性的访问(一般限制为private)
public class Person {
private String name;
private int age;
}
2、对每个值属性提供对外的公共方法访问,也就是创建一对赋取值方法,用于对私有属性的访问
public class Person{
private String name;
private int age;
public int getAge(){
return age;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age = age;
}
public void setName(String name){
this.name = name;
}
}
采用this关键字是为了解决实例变量(private String name)和局部变量(setName(String name)中的name变量)之间发生的同名的冲突
三、封装实例
/* 文件名: EncapTest.java */
public class EncapTest{
private String name;
private String idNum;
private int age;
public int getAge(){
return age;
}
public String getName(){
return name;
}
public String getIdNum(){
return idNum;
}
public void setAge( int newAge){
age = newAge;
}
public void setName(String newName){
name = newName;
}
public void setIdNum( String newId){
idNum = newId;
}
}
public方法是外部类访问该类成员变量的入口,通常情况下,这些方法被称为getter和setter方法,因此,任何要访问类中私有成员变量的类都要通过这些getter和setter方法。
/* F文件名 : RunEncap.java */
public class RunEncap{
public static void main(String args[]){
EncapTest encap = new EncapTest();
encap.setName("James");
encap.setAge(20);
encap.setIdNum("12343ms");
System.out.print("Name : " + encap.getName()+
" Age : "+ encap.getAge());
}
}
Name : James Age : 20
继承
一、概念
1、 继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。继承使代码更加简洁,提高代码的复用性(复用性主要是可以多次使用,不会再多次写同样的代码),维护性也提高。
2、类的继承格式
通过extends关键字可以申明一个类是从另外一个类继承而来的
class 父类 {
}
class 子类 extends 父类 {
}
3、继承类型
- Java不支持多继承(即不支持一个类继承多个类),但支持多重继承
- Java支持不同类继承同一个类
4、继承特性 - 子类拥有父类非private的属性、方法
- 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展
- 子类可以用自己的方式实现父类的方法
- 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)
二、继承关键字
1、extends关键字
在Java中,类的继承是单一继承,也就是说,一个子类只能拥有一个父类,所以extends只能继承一个类
2、implements关键字
使用implements关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口(接口跟接口之间采用逗号分隔)
public interface A {
public void eat();
public void sleep();
}
public interface B {
public void show();
}
public class C implements A,B {
}
3、super与this关键字
- super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类
- this关键字:指向自己的引用,引用当前对象,即它所在的方法或构造函数所属的对象实例
class Animal {
void eat() {
System.out.println("animal : eat");
}
}
class Dog extends Animal {
void eat() {
System.out.println("dog : eat");
}
void eatTest() {
this.eat(); // this 调用自己的方法
super.eat(); // super 调用父类方法
}
}
public class Test {
public static void main(String[] args) {
Animal a = new Animal();
a.eat();
Dog d = new Dog();
d.eatTest();
}
}
animal : eat
dog : eat
animal : eat
4、final关键字
final可以用来修饰变量(包括类属性、对象属性、局部变量和形参)、方法(包括类方法和对象方法)和类。使用final关键字声明类,就是把类定义定义为最终类,不能被继承,或者用于修饰方法,该方法不能被子类重写。
final class 类名 {//类体}
修饰符(public/private/default/protected) final 返回值类型 方法名(){//方法体}
- final定义的类,其中的属性、方法不是final的
三、构造器(构造方法、构造函数)
子类是不继承父类的构造器的,它只是调用(隐式或显式)。如果父类的构造器带有参数,则必须在子类的构造器中显式地通过super关键字调用父类的构造器并配以适当的参数列表。如果父类构造器没有参数,则在子类的构造器中不需要使用super关键字调用父类构造器,系统会自动调用父类的无参构造器。
class SuperClass {
private int n;
// 无参数构造器
public SuperClass() {
System.out.println("SuperClass()");
}
// 带参数构造器
public SuperClass(int n) {
System.out.println("SuperClass(int n)");
this.n = n;
}
}
// SubClass 类继承
class SubClass extends SuperClass {
private int n;
// 无参数构造器,自动调用父类的无参数构造器
public SubClass() {
System.out.println("SubClass()");
}
// 带参数构造器,调用父类中带有参数的构造器
public SubClass(int n) {
super(300);
System.out.println("SubClass(int n): " + n);
this.n = n;
}
}
// SubClass2 类继承
class SubClass2 extends SuperClass {
private int n;
// 无参数构造器,调用父类中带有参数的构造器
public SubClass2() {
super(300);
System.out.println("SubClass2()");
}
// 带参数构造器,自动调用父类的无参数构造器
public SubClass2(int n) {
System.out.println("SubClass2(int n): " + n);
this.n = n;
}
}
public class TestSuperSub {
public static void main(String[] args) {
System.out.println("------SubClass 类继承------");
SubClass sc1 = new SubClass();
SubClass sc2 = new SubClass(100);
System.out.println("------SubClass2 类继承------");
SubClass2 sc3 = new SubClass2();
SubClass2 sc4 = new SubClass2(200);
}
}
------SubClass 类继承------
SuperClass()
SubClass()
SuperClass(int n)
SubClass(int n): 100
------SubClass2 类继承------
SuperClass(int n)
SubClass2()
SuperClass()
SubClass2(int n): 200
多态
一、概念
1、多态就是同一个接口,使用不同的实例而执行不同操作。
2、多态性是对象多种表现形式的体现。现实中,比如我们按下F1 键这个动作:
- 如果当前在Flash界面下弹出的就是AS 3的帮助文档;
- 如果当前在Word下弹出的就是Word帮助;
- 在Windows下弹出的就是Windows帮助和支持。
同一个事件发生在不同的对象上会产生不同的结果。
3、多态的优点:消除类型之间的耦合关系;可替换性;可扩充性;接口性;灵活性;简化性。
4、多态存在的三个必要条件:继承;重写;父类引用指向对象
Parent p = new Child()
5、当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法
6、实例
public class Test {
public static void main(String[] args) {
show(new Cat()); // 以 Cat 对象调用 show 方法
show(new Dog()); // 以 Dog 对象调用 show 方法
Animal a = new Cat(); // 向上转型
a.eat(); // 调用的是 Cat 的 eat
Cat c = (Cat)a; // 向下转型
c.work(); // 调用的是 Cat 的 work
}
public static void show(Animal a) {
a.eat();
// 类型判断
if (a instanceof Cat) { // 猫做的事情
Cat c = (Cat)a;
c.work();
} else if (a instanceof Dog) { // 狗做的事情
Dog c = (Dog)a;
c.work();
}
}
}
abstract class Animal {
abstract void eat();
}
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
public void work() {
System.out.println("抓老鼠");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
public void work() {
System.out.println("看家");
}
}
吃鱼
抓老鼠
吃骨头
看家
吃鱼
抓老鼠
二、虚函数
1、Java中其实没有虚函数的概念,它的普通函数就相当于C++的虚函数,动态绑定是Java的默认行为。如果Java中不希望某个函数具有虚函数特性,可以加上final关键字变成非虚函数。
2、在C++中,虚函数是在某基类中声明为virtual并在一个或多个派生类中被重新定义的成员函数。
3、指向基类的指针在操作它的多态类对象时,会根据不同的类对象,调用其相应的函数,这个函数就是虚函数。
4、实例
class A{
public void FUN(){
System.out.println("FUN in A is called");
}
}
class B extends A{
public void FUN(){
System.out.println("FUN in B is called");
}
}
public class VirtualTest {
public static void main(String args[]) {
A a = new A();
B b = new B();
A p;
p = a;
p.FUN();
p = b;
p.FUN();
}
}
FUN in A is called
FUN in B is called
重写(Override)与重载(Overload)
一、重写(Override)
1、子类定义了一个与其父类中具有相同名称、参数列表和返回类型的方法,并且子类方法的实现覆盖了父类方法的实现。即外壳不变,核心重写。
2、子类可以根据需要,定义特定于自己的行为。也就是说子类能够根据需要实现父类的方法。这样在使用子类对象调用该方法时,将执行子类中的方法而不是父类中的方法。
3、重写方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常。
4、实例
package com.example.helloworld;
class Animal1{
public void move(){
System.out.println("动物可以移动");
}
}
class Dog1 extends Animal1{
public void move(){
System.out.println("狗可以跑和走");
}
}
public class override_testdog{
public static void main(String args[]){
Animal1 a = new Animal1(); // Animal 对象
Animal1 b = new Dog1(); // Dog 对象
a.move();// 执行 Animal 类的方法
b.move();//执行 Dog 类的方法
}
}
动物可以移动
狗可以跑和走
5、方法的重写规则
- 参数列表与被重写方法的参数列表必须完全相同。
- 返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的派生类。
- 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为public,那么在子类中重写该方法就不能声明为protected。
- 父类的成员方法只能被它的子类重写。
- 声明为final的方法不能被重写。
- 声明为static的方法不能被重写,但是能够被再次声明。
- 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为private和final的方法。
- 子类和父类不在同一个包中,那么子类只能够重写父类的声明为public和protected的非final方法。
- 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
- 构造方法不能被重写。
- 如果不能继承一个类,则不能重写该类的方法。
6、Super关键字的使用
当需要在子类中调用父类的被重写方法时,要使用super关键字
class Animal{
public void move(){
System.out.println("动物可以移动");
}
}
class Dog extends Animal{
public void move(){
super.move(); // 应用super类的方法
System.out.println("狗可以跑和走");
}
}
public class TestDog{
public static void main(String args[]){
Animal b = new Dog(); // Dog 对象
b.move(); //执行 Dog类的方法
}
}
动物可以移动
狗可以跑和走
二、重载(Overload)
1、重载(overloading)是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。
2、重载规则:
- 被重载的方法必须改变参数列表(参数个数或类型不一样);
- 被重载的方法可以改变返回类型;
- 被重载的方法可以改变访问修饰符;
- 被重载的方法可以声明新的或更广的检查异常;
- 方法能够在同一个类中或者在一个子类中被重载。
- 无法以返回值类型作为重载函数的区分标准。
3、实例
package com.example.helloworld;
public class OverLoading {
public int test(){
System.out.println("test1");
return 1;
}
public void test(int a){
System.out.println("test2");
}
//以下两个参数类型顺序不同
public String test(int a,String s){
System.out.println("test3");
return "returntest3";
}
public String test(String s,int a){
System.out.println("test4");
return "returntest4";
}
public static void main(String[] args){
OverLoading o = new OverLoading();
System.out.println(o.test());
o.test(1);
System.out.println(o.test(1,"test3"));
System.out.println(o.test("test4",1));
}
}
test1
1
test2
test3
returntest3
test4
returntest4
三、重写与重载的区别
区别点 | 重载方法 | 重写方法 |
---|---|---|
参数列表 | 必须修改 | 一定不能修改 |
返回类型 | 可以修改 | 一定不能修改 |
异常 | 可以修改 | 可以减少或删除,一定不能抛出新的或者更广的异常 |
访问 | 可以修改 | 一定不能做更严格的限制(可以降低限制) |
抽象类
一、概念
- 如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
- 抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。
- 由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。
- 父类包含了子类集合的常见的方法,但是由于父类本身是抽象的,所以不能使用这些方法。
- 一个类只能继承一个抽象类,而一个类却可以实现多个接口。
- 构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法。
二、继承抽象类
/* 文件名 : Employee.java */
public abstract class Employee
{
private String name;
private String address;
private int number;
public Employee(String name, String address, int number)
{
System.out.println("Constructing an Employee");
this.name = name;
this.address = address;
this.number = number;
}
public double computePay()
{
System.out.println("Inside Employee computePay");
return 0.0;
}
public void mailCheck()
{
System.out.println("Mailing a check to " + this.name
+ " " + this.address);
}
public String toString()
{
return name + " " + address + " " + number;
}
public String getName()
{
return name;
}
public String getAddress()
{
return address;
}
public void setAddress(String newAddress)
{
address = newAddress;
}
public int getNumber()
{
return number;
}
}
/* 文件名 : Salary.java */
public class Salary extends Employee
{
private double salary; //Annual salary
public Salary(String name, String address, int number, double
salary)
{
super(name, address, number);
setSalary(salary);
}
public void mailCheck()
{
System.out.println("Within mailCheck of Salary class ");
System.out.println("Mailing check to " + getName()
+ " with salary " + salary);
}
public double getSalary()
{
return salary;
}
public void setSalary(double newSalary)
{
if(newSalary >= 0.0)
{
salary = newSalary;
}
}
public double computePay()
{
System.out.println("Computing salary pay for " + getName());
return salary/52;
}
}
/* 文件名 : AbstractDemo.java */
public class AbstractDemo
{
public static void main(String [] args)
{
Salary s = new Salary("Mohd Mohtashim", "Ambehta, UP", 3, 3600.00);
Employee e = new Salary("John Adams", "Boston, MA", 2, 2400.00);
System.out.println("Call mailCheck using Salary reference --");
s.mailCheck();
System.out.println("\n Call mailCheck using Employee reference--");
e.mailCheck();
}
}
Constructing an Employee
Constructing an Employee
Call mailCheck using Salary reference --
Within mailCheck of Salary class
Mailing check to Mohd Mohtashim with salary 3600.0
Call mailCheck using Employee reference--
Within mailCheck of Salary class
Mailing check to John Adams with salary 2400.
三、抽象方法
1、父类中包含一个特别的成员方法,该方法的具体实现由它的子类确定,那么就在父类中声明该方法为抽象方法。
2、Abstract关键字也可用来声明抽象方法,抽象方法只包含一个方法名,而没有方法体。
3、抽象方法没有定义,方法名后面直接跟一个分好,而不是花括号。
4、声明抽象方法会造成以下两个结果:
- 如果一个类包含抽象方法,那么该类必须是抽象类
- 任何子类必须重写父类的抽象方法,或者声明自身为抽象类
5、在上述实例中,如果Salary类继承了Employee类,那么它必须实现computePay()方法
/* 文件名 : Salary.java */
public class Salary extends Employee
{
private double salary; // Annual salary
public double computePay()
{
System.out.println("Computing salary pay for " + getName());
return salary/52;
}
//其余代码
}
接口
一、概念
1、接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。
2、接口不是类。类描述对象的属性和方法,接口则包含类要实现的方法。
3、除非实现接口的类是抽象类,否则该类要定义接口中的所有方法。
4、接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。
5、在Java中,接口类型可用来声明一个变量,他们可以成为一个空指针,或是被绑定在一个以此接口实现的对象。
6、接口与类相似点:
- 一个接口可以有多个方法。
- 接口文件保存在.java结尾的文件中,文件名使用接口名。
- 接口的字节码文件保存在.class结尾的文件中。
- 接口相应的字节码文件必须在与包名称相匹配的目录结构中。
7、接口与类的区别:
- 接口不能用于实例化对象。
- 接口没有构造方法。
- 接口中所有的方法必须是抽象方法,Java 8之后,接口中可以使用default关键字修饰的非抽象方法。
- 接口不能包含成员变量,除了static和final变量。
- 接口不是被类继承了,而是要被类实现。
- 接口支持多继承。
8、接口特性
- 接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为public abstract(只能是public abstract,其他修饰符都会报错)。
- 接口中可以含有变量,但是接口中的变量会被隐式的指定为public static final变量(并且只能是public,用private修饰会报编译错误)。
- 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。
9、抽象类和接口的区别
- 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。
- 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的。
- 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。
- 一个类只能继承一个抽象类,而一个类却可以实现多个接口。
二、接口的声明
1、语法格式
[可见度] interface 接口名称 [extends 其他的接口名] {
// 声明变量
// 抽象方法
}
- 接口是隐式抽象的,声明接口时,不必使用abstract关键字
- 接口中的方法也是隐式抽象的,声明时同样不需要abstract关键字
- 接口中的方法都是公有的
2、实例
/* 文件名 : Animal.java */
interface Animal {
public void eat();
public void travel();
}
三、接口的实现
类使用implements关键字实现接口。在类声明中,Implements关键字放在class声明后面。
...implements 接口名称[, 其他接口名称, 其他接口名称..., ...] ...
package com.example.helloworld;
/* 文件名 : MammalInt.java */
interface Animal2{
public void eat();
public void travel();
};
public class MammalInt implements Animal2{
public void eat(){
System.out.println("Mammal eats");
}
public void travel(){
System.out.println("Mammal travels");
}
public int noOfLegs(){
return 0;
}
public static void main(String args[]){
MammalInt m = new MammalInt();
m.eat();
m.travel();
}
}
Mammal eats
Mammal travels
重写接口中声明的方法时,需要注意以下规则:
- 类在实现接口的方法时,不能抛出强制性异常,只能在接口中,或者继承接口的抽象类中抛出该强制性异常。
- 类在重写方法时要保持一致的方法名,并且应该保持相同或者相兼容的返回值类型。
- 如果实现接口的类是抽象类,那么就没必要实现该接口的方法。
在实现接口的时候,也要注意一些规则:
- 一个类可以同时实现多个接口。
- 一个类只能继承一个类,但是能实现多个接口。
- 一个接口能继承另一个接口,这和类之间的继承比较相似。
四、接口的继承
接口的继承使用extends关键字,子接口继承父接口的方法。
// 文件名: Sports.java
public interface Sports
{
public void setHomeTeam(String name);
public void setVisitingTeam(String name);
}
// 文件名: Football.java
public interface Football extends Sports
{
public void homeTeamScored(int points);
public void visitingTeamScored(int points);
public void endOfQuarter(int quarter);
}
// 文件名: Hockey.java
public interface Hockey extends Sports
{
public void homeGoalScored();
public void visitingGoalScored();
public void endOfPeriod(int period);
public void overtimePeriod(int ot);
}
Hockey接口自己声明了四个方法,从Sports接口继承了两个方法,这样,实现Hockey接口的类需要实现六个方法。相似的,实现Football接口的类需要实现五个方法,其中两个来自于Sports接口。
五、接口的多继承
类的多继承是不合法的,但接口允许多继承。
public interface Hockey extends Sports, Event
六、标记接口
标记接口是没有任何方法和属性的接口.它仅仅表明它的类属于一个特定的类型,供其他代码来测试允许做一些事情。简单来说就是给某个对象打个标记,使对象拥有某个或某些特权。
标记接口主要用于以下两种目的:
- 建立一个公共的父接口
- 向一个类添加数据类型
枚举
一、概念
1、枚举是个特殊的类,一般表示一组常量,如一年的12个月份。
2、枚举类使用enum关键字来定义,各常量使用","来分割。
enum Color
{
RED, GREEN, BLUE;
}
public class Test
{
// 执行输出结果
public static void main(String[] args)
{
Color c1 = Color.RED;
System.out.println(c1);
}
}
RED
二、内部类中使用枚举
枚举类也可以声明在内部类中
public class Test
{
enum Color
{
RED, GREEN, BLUE;
}
// 执行输出结果
public static void main(String[] args)
{
Color c1 = Color.RED;
System.out.println(c1);
}
}
RED
每个枚举都是通过Class在内部实现的,且所有的枚举值都是public static final的。
三、迭代枚举元素
使用for语句来迭代枚举元素
enum Color
{
RED, GREEN, BLUE;
}
public class MyClass {
public static void main(String[] args) {
for (Color myVar : Color.values()) {
System.out.println(myVar);
}
}
}
RED
GREEN
BLUE
四、在switch中使用枚举类
enum Color
{
RED, GREEN, BLUE;
}
public class MyClass {
public static void main(String[] args) {
Color myVar = Color.BLUE;
switch(myVar) {
case RED:
System.out.println("红色");
break;
case GREEN:
System.out.println("绿色");
break;
case BLUE:
System.out.println("蓝色");
break;
}
}
}
蓝色
五、values(), ordinal() 和valueOf()方法
- values()返回枚举类中所有的值。
- ordinal()方法可以找到每个枚举常量的索引,就像数组索引一样。
- valueOf()方法返回指定字符串值的枚举常量。
enum Color
{
RED, GREEN, BLUE;
}
public class Test
{
public static void main(String[] args)
{
// 调用 values()
Color[] arr = Color.values();
// 迭代枚举
for (Color col : arr)
{
// 查看索引
System.out.println(col + " at index " + col.ordinal());
}
// 使用 valueOf() 返回枚举常量,不存在的会报错 IllegalArgumentException
System.out.println(Color.valueOf("RED"));
// System.out.println(Color.valueOf("WHITE"));
}
}
RED at index 0
GREEN at index 1
BLUE at index 2
RED
六、枚举类成员
1、枚举跟普通类一样可以用自己的变量、方法和构造函数,构造函数只能使用private访问修饰符,所以外部无法调用。
2、枚举既可以包含具体方法,也可以包含抽象方法。如果枚举类具有抽象方法,则枚举类的每个实例都必须实现它。
enum Color_2
{
RED, GREEN, BLUE;
// 构造函数
private Color_2()
{
System.out.println("Constructor called for : " + this.toString());
}
public void colorInfo()
{
System.out.println("Universal Color");
}
}
public class ColorTest_2
{
// 输出
public static void main(String[] args)
{
Color_2 c1 = Color_2.RED;
System.out.println(c1);
c1.colorInfo();
}
}
Constructor called for : RED
Constructor called for : GREEN
Constructor called for : BLUE
RED
Universal Color
标签:JAVA,思想,void,System,接口,面向对象,方法,public,out
From: https://www.cnblogs.com/shihongpin/p/18360858