面向对象的三大特征:继承,封装,多态
封装:变量定义private ; set/get方法; 构造方法
封装的实现:
-
private的变量
-
提供set/get方法
练习:输出矩形的周长和面积
public class Rectangle {
private int chang;
private int kuan;
public int getChang() {
return chang;
}
public void setChang(int chang) {
if(chang>=0) {
this.chang = chang;
}
else {
System.out.println("长度错误");
return;
}
}
public int getKuan() {
return kuan;
}
public void setKuan(int kuan) {
if(kuan>=0) {
this.kuan = kuan;
}
else {
System.out.println("宽度错误");
return;
}
}
public int getMian() {
return chang*kuan;
}
public int getZhou() {
return (chang+kuan)*2;
}
}
测试类
public class TestRectangle {
public static void main(String[] args) {
// TODO Auto-generated method stub
Rectangle r=new Rectangle();
r.setChang(2);
r.setKuan(3);
System.out.println("面积"+r.getMian());
System.out.println("周长"+r.getZhou());
}
}
继承:
特点:
-
什么继承:由已有类产生新类,这种机制叫继承
-
父类子类:已有类->父类 新类->子类
-
继承性:子类可以继承父类的所有成员(构造方法不能继承),有些方法不可以使用的
-
Object是顶级类,是所有类的父类
-
满足一种关系: is a
-
extends 关键字
-
Java 单继承, 每个子类只有一个直接父类。例如下面代码将会引起编译错误。
class SubClass extends Basel , Base2 , Base3{ . .. }
super
super:表示父类对象
super.成员
super(参数):必须是子类构造方法的第一条有效语句
访问修饰符 (visibility)
private 变量,方法 本类
default 类,变量,方法 同一个包
protected 变量,方法 同一个包,不同包(继承关系)
public 类,变量,方法 任何地方
方法重写
继承关系:
父类和子类 方法名相同,参数列表相同
方法的返回类型如果是基本数据类型同(如果是继承关系,引用数据类型,子类的类型要<=父类的)
public class A{
}
public class B extends A{
}
public class c{
public A f() {
return null;
}
}public class D extends C{
public B f() {
return null;
}
}
子类方法的访问修饰符>=父类
异常:子类方法的异常(非运行时异常)<=父类
子类和父类的方法可以重载
为什么重写?扩展父类方法的功能 Person和Student.java
私有方法不能被重写
继承关系中构造方法的调用规则
1)子类创建对象时,不管创建对象时是否传参,都总是默认调用父类无参的构造方法
2)如果父类没有无参的构造方法,那么子类使用使用super()调用指定的构造方法
代码1)
public class A {
int x;
int y;
public A() {
System.out.println("A1");
}
public A(int x,int y){
System.out.println("A");
}
}
class B extends A{
public B(int x,int y){
System.out.println("B");
}
}
B b=new B(1,2);
//B b1=new B(); error
结果为:
A1
B
代码2)
public class A {
int x;
int y;
public A(int x,int y){
System.out.println("A");
}
}
class B extends A{
public B(int x,int y){
//必须加上这句 super(x,y);
super(x,y);
System.out.println("B");
}
}
B b=new B(1,2);
结果为:
A
B
在2)时,即使父类有了无参构造,结果依然是 A B,因为有super(x,y)
构造方法练习
class MyClass{
public int value;
}
public class TestMyClass{
public static void main(String args[]){
MyClass mc1 = new MyClass();
MyClass mc2 = new MyClass(10); //error
System.out.println(mc1.value);
System.out.println(mc2.value);
}
}
构造方法的调用
class Super{
public Super(){
System.out.println("Super()");
}
public Super(String str){
System.out.println("Super(String)");
}
}
class Sub extends Super{
public Sub(){
System.out.println("Sub()");
}
public Sub(int i){
this();
System.out.println("Sub(int)");
}
public Sub(String str){
//如果没有super(str);这句,就默认掉父类无参构造,结果就为Super() Sub(String)
//有了这句,就调用父类有参构造
super(str);
System.out.println("Sub(String)");
}
}
public class TestSuperSub{
public static void main(String args[]){
Sub s1 = new Sub(); //Super() Sub()
Sub s2 = new Sub(10); //Super() Sub() Sub(int)
Sub s3 = new Sub("hello"); //Super(String) Sub(String)
}
}
多态:
定义:一种类型的变量可以指向不同的对象
父类声明=子类创建
Animal a1=new Dog();
Animal a2=new Bird();
编译时多态:方法的重载
class A{
void f(){
…(“f”);
}
void f(int x){
…(“f”+x);
}
}
A a1=new A();
A a2=new A();
a1.f();
a2.f(1);
运行时多态:方法的重写
在Animal类中定义eat ,Dog和Bird类重写了此方法
Animal a1=new Dog();
Animal a2=new Bird();
a1.eat();
a2.eat();
在编译时,看变量的声明类型
运行时,如果子类重写了父类的方法,动态绑定到子类上,运行子类的方法
对于变量,永远是谁声明就找谁
多态练习:
class Super{
public void method(){
System.out.println("method() in Super");
}
public void method(int i){
System.out.println("method(int) in Super");
}
}
class Sub extends Super{
public void method(){
System.out.println("method() in Sub");
}
public void method(String str){
System.out.println("method(String) in Sub");
}
}
public class TestSuperSub{
public static void main(String args[]){
Super s = new Sub();
s.method(10);
s.method();
s.method("hello");//编译错误
}
}
练习动物:
public class Animal {
public void eat() {
System.out.println("吃");
}
}
public class Bird extends Animal{
public void eat() {
System.out.println("吃虫子");
}
public void b() {
System.out.println("bird");
}
}
public class Dog extends Animal{
public void eat() {
System.out.println("吃肉骨头");
}
public void d() {
System.out.println("dog");
}
}
public class AnimalTest {
public static void main(String[] args) {
Animal a=new Dog();
Animal b=new Bird();
Feeder f=new Feeder();
f.feed(a);
f.feed(b);
f.test(a); //dog
f.test(b); //bird
f.test2(); //java.lang.ClassCastException
}
}
多态的应用
方法的参数定义为父类类型或者接口类型
public void feed(Animal animal){
animal.eat();
}
对象造型:(父子类之间的强制转换)
通过instanceof判断
public void test(Animal animal) {
if(animal instanceof Dog) {
((Dog) animal).d();
}
if(animal instanceof Bird) {
((Bird) animal).b();
}
}
public void test2() {
Dog dog=new Dog();
Bird bird=new Bird();
//兄弟类不能强制转换,编译错误
//bird=(Bird)dog; //error
//继承关系,父类可以强制转换成子类对象,但是可能会发生运行时异常
Animal dog2=new Dog();
Animal bird2=new Bird();
bird2=(Bird)dog2; //运行时异常
}
Feeder f=new Feeder();
f.test(a); //dog
f.test(b); //bird
f.test2(); //java.lang.ClassCastException
static:修饰变量,方法,静态块
占内存不释放
使用:类名.static的成员
1.修饰变量:
变量:成员-> 类变量(静态变量): 由static修饰的成员变量; 实例变量 :没有static修饰
局部
类变量和实例变量的区别:
类变量对所有对象共享,公用
实例变量是归对象所有,不是公用
静态变量可以由类名调用
静态变量:类加载器加载类的时候初始化的
int x;
static int y;
public static void main(String[] args) {
DemoStatic d1=new DemoStatic();
d1.x=10;
d1.y=10;
DemoStatic d2=new DemoStatic();
d2.x=11;
d2.y=11;
System.out.println(d1.x+","+DemoStatic.y);
System.out.println(d2.x+","+DemoStatic.y);
}
结果:
10,11
11,11
练习:实现堆对象的计数功能
public class DemoStatic {
static int count = 0;
DemoStatic(){
count++;
}
public static void main(String[] args) {
DemoStatic d1=new DemoStatic();
DemoStatic d2=new DemoStatic();
System.out.println(DemoStatic.count);
}
}
变量的初始化过程:
static int x=5;
int x = 6;
2.修饰方法
静态方法:由static修饰 ,直接访问静态成员
实例方法:没有static修饰
int x = 1;
static int y = 2;
void f(){
}
static void f2(){
}
void test1(){
x = 2; //ok
y = 3;
f(); //ok
f2();
}
static void test2(){
x = 2; //error
y = 3;
f(); //error
f2();
}
静态方法是否可以重载?可以
public static void test1() {
}
public static void test1(String str) {
}
静态方法是否可以继承?可以
public class DemoStatic3 {
public static void test1() {
System.out.println("1111");
}
public static void main(String[] args) {
//Demo d=new Demo();
Demo.test1();
}
}
class Demo extends DemoStatic3{
}
结果:1111
静态方法是否可以重写?不能
class Demo extends DemoStatic3{
public static void test1() {
System.out.println("222222222");
}
}
public class DemoStatic3 {
public static void test1() {
System.out.println("1111");
}
public static void main(String[] args) {
DemoStatic3 demo=new Demo();
demo.test1();
}
}
结果:1111
构造方法是否可以定义静态的?不可以
public static DemoStatic3() {
}
报错,所以不可以
静态方法是否可以使用this,super? 不可以
int x=1;
public static void test1() {
this.x=3;
//System.out.println("1111");
}
报错
练习:
class TestSuper {
public static void ma(){
System.out.println("Super ma");
}
public void mb(){
System.out.println("Super mb");
}
}
class TestSub extends TestSuper {
public static void ma(){
System.out.println("Sub ma");
}
public void mb(){
System.out.println("Sub mb");
}
}
public class Test {
public static void main(Stirng[] args){
TestSuper ts = new TestSub();
ts.ma(); //super ma
ts.mb(); //sub mb
}
}
3.静态块
static{
}
写到类体中,在类加载时,仅执行一次
public class Hello{
static{
//输出hello
System.out.println("hello");
}
}
练习:
public class A{
static int x = 9;
static{
x = 10;
y = 90;
z = 20;
}
static int y = 100;
static int z;
}
x = 10 y = 100,z = 20
public class Test{
private static Test tester = new Test(); //step 1
private static int count1; //step 2
private static int count2 = 2; //step 3
public Test(){ //step 4
count1++;
count2++;
System.out.println("" + count1 + count2); // 1 1
}
public static Test getTester(){ //step 5
return tester;
}
public static void main(String[] args){
Test.getTester();
}
静态块和构造块
父类的静态块->子类静态块->父类的构造块->父类的构造方法->子类的构造块->子类的构造方法
class A{ 1 11 2 3 22 33
static{
........("1");
}
{
.......("2");
}
public A(){
.......("3");
}
}
class B extends A{
static{
........("11");
}
{
.......("22");
}
public B(){
.......("33");
}
}
new B();
练习:
class A{
static D d;
static {.....("A1"); d = new D();}
{.........("A2");}
public A(){.........("A3");}
}
class B extends A{
static C c = new C();
static {.....("B1");}
{.........("B2");}
public B(){.........("B3");}}
class C{
public C(){........("C");}
}
class D extends C{
public D(){........("D");}
}
new B(); A1 C D C B1 A2 A3 B2 B3
final:
final可以修饰类,方法,变量
fianl修饰的变量:常量 常量值不变
(对于数组来说,指的是内存地址,并不是里面的元素)
final int NUM={1,2,3};
void f(){
NUM[0]=11;
}
Test t=new Test();
t.f();
System.out.println(Arrays.toString(t.NUM));
常量名:一般名字的所有字母都大写,如果有多个单词组成,单词之间用_
格式:final int PRICE = 10;
特点:不能改
final修饰的方法:不能重写
final修饰类:不能被继承
final 修饰的方法可以被继承
final练习
public class Sp {
public final void m1(){
System.out.println("m1() in Super");
}
public void m1(int i){
System.out.println("m1(int) in Super");
}
}
public class Sb extends Sp{
public void m1(int i){
System.out.println("m1(int) in Sub");
}
public void m1(double d){
System.out.println("m1(double) in Sub");
}
}
public class Test {
public static void main(String args[]){
//如果这是Sp s = new Sb(); 则下面的s.m1()则报错
Sb s = new Sb();
s.m1(); //m1() in Super
s.m1(10); //m1(int) in Sub
s.m1(1.5); //m1(double) in Sub
}
}
abstract
1.抽象方法:由abstract修饰的方法
2.特点:没有方法体
3.抽象类:由abstract修饰的类 ------ 模块
4.特点:不能创建对象
5.抽象类中可以没有抽象方法
6.抽象类由子类创建对象
7.子类可以创建对象,要实现所有的抽象方法,
没有实现全部的抽象方法,当前类声明为抽象类
练习:定义一个类表示形状,提供获取周长和面积的方法,
然后给这个类提供子类:矩形 - 正方形,椭圆 - 圆形
1)定义抽象类Shape,两个抽象方法double getArea()和
double getLength()
2)定义子类Rectangle,(构造方法传参)
3)定义子类Oval,(构造方法传参) 周长:3.14ab
面积:23.14b+4*(a-b)
4)定义Rectangle的子类Square
5)定义Oval的子类Circle
6)测试:计算各种图形的面积周长
public abstract class Shape {
public abstract double getArea();
public abstract double getLength();
}
public class Rectangle extends Shape{
double chang;
double kuan;
public Rectangle(double chang,double kuan) {
this.chang=chang;
this.kuan=kuan;
}
public double getArea() {
// TODO Auto-generated method stub
return chang*kuan;
}
public double getLength() {
// TODO Auto-generated method stub
return 2*(chang+kuan);
}
}
public class Square extends Rectangle{
double s;
public Square(double s) {
super(s,s);
}
}
public class Test {
public static void main(String[] args) {
Shape r=new Rectangle(1,2);
System.out.println(r.getArea());
System.out.println(r.getLength());
Rectangle s=new Square(1);
System.out.println(s.getArea());
System.out.println(s.getLength());
}
}
interface
1.定义接口
interface 接口名{
变量:int x = 10; 默认public static final修饰的
方法:抽象方法:默认访问修饰符:public abstract
普通方法:jdk8开始 default或者static
}
2.使用接口 implements
实现接口的类,要实现接口中的所有方法,才可以创建对象
如果不实现接口中的所有方法,当前类必须为abstract的类
3.接口和接口之间是继承关系
interface A{}
interface B extends A{}
interface C{}
4.类和接口之间是实现,可以实现多个接口
class Demo extends Object1 implmenents B,C{}
练习:
1.利用接口做参数,写个计算器,能完成加减乘除运算。
(1)定义一个接口ICompute
含有一个方法int computer(int n, int m)。
(2)设计四个类Add,Sub, Mul,Div分别实现此接口,完成加减乘除运算。
(3)设计一个类UseCompute,类中含有方法:
public void useCom(ICompute com, int one, int two),
此方法能够用传递过来的对象调用computer方法完成运算,并输出运算的结果。
(4)设计一个主类Test,调用UseCompute中的方法useCom来完成加减乘除运算。
public interface IComputer {
int computer(int n,int m);
}
public class Add implements IComputer{
public int computer(int n, int m) {
return n+m;
}
}
public class Sub implements IComputer{
public int computer(int n, int m) {
// TODO Auto-generated method stub
return n-m;
}
}
public class UserComputer {
public void useCom(IComputer com,int one,int two) {
System.out.println(com.computer(one, two));
}
public static void main(String[] args) {
UserComputer u=new UserComputer();
u.useCom(new Add(), 2, 1);
u.useCom(new Sub(), 2, 1);
u.useCom(new Mul(), 2, 1);
u.useCom(new Div(), 2, 1);
}
}
2.按如下要求编写Java程序:
(1)定义接口A,里面包含值为3.14的常量PI和
抽象方法double doubleArea(double radius)。//πr*r
(2)定义接口B,里面包含
抽象方法void setColor(String c)。
(3)定义接口C,该接口继承了接口A和B,
里面包含抽象方法
void volume(double radius,double height)//πrrh
(4)定义圆柱体类Cylinder实现接口C
public interface A {
double PI=3.14;
double doubleArea(double radius);
}
public interface B {
void setColor(String c);
}
public interface C extends A,B{
double volum(double radius,double height);
}
public class Cylinder implements C{
String c;
public double doubleArea(double radius) {
// TODO Auto-generated method stub
return A.PI*radius*radius;
}
public void setColor(String c) {
// TODO Auto-generated method stub
System.out.println(c);
}
public double volum(double radius, double height) {
// TODO Auto-generated method stub
return A.PI*radius*radius*height;
}
}
接口jdk8新特性:
1.接口中可以定义普通方法
default void test(){
System.out.println(“test”);
}
static void test2(){
System.out.println(“test2”);
}
2.default修饰的方法由实现类调用
static修饰的方法可以由接口名直接调用
接口不能创建对象
3.实现类的接口和父类定义了同名方法,如何访问
访问父类的方法
4.如果两个接口中都定义了同名方法,如何访问?出现编译错误
子类必须重写同名方法
5.函数式接口:
接口中只有一个抽象方法->lambda表达式
接口和抽象类的区别
抽象类 接口
模板类 不同类型的公共的行为(规范JDBC)
不能多继承 可以多继承
有构造方法 没有构造方法
变量是普通的变量 都是公有静态常量
普通方法 普通方法由 default或者static修饰
抽象方法没有默认访问修饰符 访问修饰符是public
内部类
1.类体内部类
没有static修饰的内部类
outclass.innerclass name = new outclass().new innerclass();
public class Demo1 {
private int x;
public static int y;
//可以访问外部类的成员
//不可以定义静态成员,但是可以定义静态常量
//Demo1.Inner inner = new Demo1().new Inner();
class Inner{
final static int b =0;
int a;
void test3(){
x = 0;
y = 9;
System.out.println("test3");
}
}
public static void main(String[] args) {
Demo1.Inner inner = new Demo1().new Inner();
inner.test3();
}
}
有static修饰的内部类
outclass.innerclass name = new outclass.innerclass();
public class Demo2 {
public int x ;
public static int y;
//可以访问外部静态成员
//可以定义静态和非静态成员
//Demo2.Inner inner = new Demo2.Inner();
static class Inner{
int a=0;
static int b = 9;
void f(){
y = 9;
System.out.println(y);
}
}
public static void main(String[] args) {
Demo2.Inner inner = new Demo2.Inner();
inner.f();
}
}
2.方法内的内部类
public class Demo3 {
int x = 9;
static int y = 9;
void f(){
int a = 9;
//可以访问外部类的成员
//不能定义静态成员,但是可以定义静态常量
//方法内的变量被内部类访问后,变量别表示为常量
class Inner{
int b=0; //jdk1.7之后默认常量
final static int c = 0;
void f(){
int r = a+0;
x = 0;
y = 9;
System.out.println("!!!!!");
}
}
new Inner().f();
}
public static void main(String[] args) {
new Demo3().f();
}
}
3.匿名类
匿名类可以继承父类,也可以实现接口,可以创建对象
父类类型(接口类型) 变量名 = new 父类类型(接口类型)(){
匿名类的类体;
}
public class Demo4 {
//创建子类的对象
Object obj = new Object(){
@Override
public String toString() {
return "Hello";
}
};
IDemo demo = new IDemo(){
@Override
public void f() {
System.out.println("接口方法的实现");
}
};
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(new Demo4().obj.toString()); //hello
new Demo4().demo.f(); //接口方法的实现
}
//方法的参数使用匿名类实现
public void test(IDemo demo){
demo.f();
}
public static void main(String[] args) {
Demo4 demo4 = new Demo4();
demo4.test(new IDemo(){
@Override
public void f() {
System.out.println("接口方法的实现");
}
});
}
}
匿名类练习
interface IA{ void ma(); }
class MyClass {
public static void method(IA ia){
System.out.println(“in method” );
ia.ma();
}
}
public class TestInnerClass{
public static void main(String args[]){
MyClass.method(new IA(){
public void ma(){
System.out.println(“ma in anonymous inner class” );
}
});
class MyMaClass implements IA{
public void ma(){
System.out.println(“ma in local inner class” );
}
}
MyClass.method(new MyMaClass());
}
}