对于面向对象程序首先就要了解什么类,什么是对象,以及面向对象的三个基本特征?
类就是将现实生活中事物抽象的在程序中描述。而对象就是一个个描述该事物的个体。
//定义一个对人的描述的类
class Person{
private String name; //姓名
private int age; //年龄
private String sex; //性别
public void sleep(){ //睡觉的方法
System.out.println("睡觉");
}
}
public class PersonTest{
public static void main(String[] args) {
Person p1=new Person(); //类的实例化
Person p2=new Person();
}
}
上面的代码中可以看出Person类是在程序中对人的描述,在main方法中创建了一个个事物的个体,p1,p2就相当于有叫张三和李四的人。
再来看一下内存的分配情况:当程序在main函数中运行到Person p1=new Person()时将在堆内存中创建一个新的对象new Person(),在栈内存中创建了一个对象的引用p1。堆内存中的首地址赋值给栈内存对象的引用p1。
有人会问为什么main方法的修饰符必须是public 而且还是静态的?
static 特点
1)随着类的加载而加载。(会随着类的消失而消失,说明它的生命周期最长)
2)优先于对象存在。
3)可以直接被类名所调用。
实例变量和类变量的区别:
1)存放位置:类变量随着类的加载而存在于方法区中。实例变量随着对象的建立而存在于堆内存中。
2)生命周期:类变量生命周期最长,随着类的消失而消失。实例变量生命吗周期随着对象的消失而消失
静态使用注意事项
1)静态方法只能访问静态成员。非静态方法既可以访问静态也可以访问非静态。
2)静态方法中不可以定义this、super关键字。因为静态优先于对象存在,所以静态方法中是不可以出现this、super。
静态的利处在于对对象的共享数据进行单独空间的存储,节省空间,没有必要每一个对象中都存储一份,可以直接被类名调用。
静态的弊处在于生命周期过长,访问出现局限性。(静态虽好,只能访问静态)
public static void main(String args[])方法由于被java虚拟机执行所以他的访问权限必须是public,虚拟机在执行该方法时不需要创建对象所以该方法必须是static。下面程序将会打印什么?:
public class Test{
public static void main(String[] args) {
for(int i=0;i<args.length;i++){
System.out.println(arg);
}
}
}
在控制台上先进行编译再运行java Test haha hehe将会在控制台上看到运行后的结果是haha hehe,可以得出结论此方法接收一个String类型的数组参数,该数组保存了执行java命令时传递给所运行的类的参数。
java的三大特性分别是:封装、继承、多态
封装:封装有时也叫数据隐藏。 我个人感觉就像是一副锁只提供了打开和关闭两个功能,至于怎么去实现这两个功能我们不知道,这样就提高了安全性。先来看下面代码
class Person{
int age=0;
}
public class PersonTest{
public static void main(String[] args) {
Person p=new Person();
p.age=10;
System.out.println(p.age);
}
}
运行后的结果:10
从结果可以看出Person类中的字段age数据被修改了这样会导致数据的安全性问题,就好比玩游戏要想升级就必须获得经验,不能使用外部随意修改等级。
再来看下面的代码
class Person{
private int age=0;
}
public class PersonTest{
public static void main(String[] args) {
Person p=new Person();
p.age=10;
System.out.println(p.age);
}
}
运行后报错,这说明使用了private修饰后外部类将不能对其操作,那么如何能实现封装性又能对其操作?那么需要设计符合自己要求的方法,也就是说想要操作里面的数据必须按照要求来。下面设计获取字段和设置字段两个方法:
class Person{
private int age=0;
public int getAge() { //定义一个获取字段的方法
return age;
}
public void setAge(int age) { //定义一个设置字段的方法
if(age<0||age>10) //对传入的字段进行判断是否符合
return;
this.age = age;
}
}
public class PersonTest{
public static void main(String[] args) {
Person p=new Person();
p.setAge(12); //对字段进行设置
System.out.println(p.getAge());//获取字段的值
p.setAge(3); //对字段进行设置
System.out.println(p.getAge()); //获取字段的值
}
}
运行后的结果是:0 3
从结果可以看出 第一次设置的值没有效果,因为第一设置的值不符合内部要求是不会进行修改里面的字段的,实现了封装性提高了安全。
继承:是用来表示特殊与一般的关系,Object类是除Object类外的所有类的超类,继承的关键字是extends,只允许单继承,也可以多层继承,一个类可以被多个类继承,提高了代码的复用性加快了开发速度,减少了代码出错的机会
class Person{
public int age;
}
class Student extends Person{
public String id;
}
public class PersonTest{
public static void main(String[] args) {
Student stu=new Student(); //创建一个Student对象
stu.age=10; //对该对象中的age字段进行赋值
System.out.println(stu.age); //打印该对象赋值后的age值
}
}
从程序中可以看出Student类继承了Person类,表面上Student类中是没有age字段的,而在主程序中该Student类age字段赋值并能打印出来,说明子类是继承了父类的字段。同理也是可以继承公有的构造函数和方法。那么如果字段是被private修饰的呢?
如果将字段和方法私有化,即将上面程序改成private int age其他不变,通过在控制台上编译是报错的,这说明私有字段是不能被继承的。可以得出结论,凡是在父类中被private修饰终不能被子类继承。
构造方法:
构造方法的特点:
1、构造方法名要与类名相同。
2、构造方法无返回值。
3、不能在构造方法中使用return返回一个值。
4、子类是不能继承父类的构造方法,所以才有super关键字。
构造方法的重载:
class Person{
private int age;
public Person(int age){ //构造方法
this.age=age;
}
public Person(){
}
public int getAge() {
return age;
}
}
class Student extends Person{
private int id;
public Student(int age,int id) {
super(age); //对于super关键字我是这么理解的,引用父类的构造方法,如果super不传参就引用父类的无参的构造方法,如果传参就引用父类中的有参构造方法,除Object类外构造方法中第一行是默认一个隐式super()
this.id=id; //this关键字代表的是当前类对象的引用,这一行的意思是将传进来的参数赋值给了当前对象中的id字段。
}
public int getId() {
return id;
}
}
public class PersonTest{
public static void main(String[] args) {
Student stu=new Student(12,10); //创建一个Student对象
System.out.println(stu.getAge());;
}
}
运行后的结果是:12
可以得出结论构造方法的重载的特点在于构造方法名相同,参数个数不同。
重载和重写有什么不同?
class Person{
public String name;
public void sleep(){
System.out.println(name);
}
}
class Student extends Person{
public void sleep(){
System.out.println(name+"在睡觉");
}
}
public class PersonTest{
public static void main(String[] args) {
Student stu=new Student();
stu.name="张三";
stu.sleep();
}
}
从两个程序比较可以以下不同:
1、重载是方法名相同参数个数不同而重写是方法名和参数是相同的
2、重载在一个类中实现,而重写是子类对父类中的方法重新定义方法体中的内容
3、可以对构造方法进行重载,而在子类中是不能对父类中的构造方法重写
抽象类和接口:
抽象类:一个类被abstract关键字修饰,这个类即为抽象类,不能创建该类的实例对象。同理一个方法被修饰,那么这个方法为抽象方法。一个普通类中如果有一个方法为抽象方法,那么这个类必定为抽象类,如果一个类继承了抽象类,那么这个类必须重写抽象类中的抽象方法,抽象类的用处在于在不能对事物进行具体的描述时采用抽象方法来描述
abstract class Person{ //抽象类
abstract void sleep(); //抽象方法
abstract void eat();
}
class Student extends Person { //子类继承了抽象类的父类
void eat() { //重写父类的抽象法方法
}
void sleep() {
}
}
接口:一个类被interface关键字修饰,那么这个类就成为了接口,接口中的方法必须全部是抽象的,如果一个类实现了接口,那么这个类必须对接口中的所有方法进行重写,一个类可以实现多个接口,接口的用处主要用于实现功能的扩展。
class NetWork implements Slot{
public void add() {
}
}
interface Slot{
abstract void add();
}
内部类:
先来看个内部类的代码
class Outer{
class Inter{
public void print(){
System.out.println("内部类中的方法");
}
}
public void test(){
Inter in=new Inter();
in.print();
}
}
public class Test{
public static void main(String[] args) {
Outer out=new Outer();
out.test();
}
}
运行结果是:内部类中的方法
可以看出,内部类就是在一个类中再写一个类,那么内部类有什么特点呢?
class Outer{
int a=2;
public class Inter{
int b=3;
public void print(){
System.out.println(a);
}
}
public void test(){
//System.out.println(b);
//Inter in=new Inter();
//System.out.println(in.b);
}
}
public class Test{
public static void main(String[] args) {
Outer.Inter in=new Outer().new Inter();
in.print();
}
}
运行结果是:2
1、内部类可以直接访问外部类中的成员,而外部类不可以直接访问内部类的成员,只有通过实例化内部类对象,并用对象.成员才能访问class Outer{
int a=2;
private class Inter{
int b=3;
public void print(){
System.out.println(a);
}
}
public void test(){
new Inter().print();
}
}
public class Test{
public static void main(String[] args) {
Outer out=new Outer();
out.test();
}
}
2、当内部类被private修饰时,外部是不知道内部有哪些功能的,如果内部类不想被外面操作那么可以用private修饰。
class Outer{
int a=2;
public void test(final int c){
class Inter{
int b=4;
public void print(){
System.out.println(c);
}
}
}
}
public class Test{
public static void main(String[] args) {
Outer out=new Outer();
out.test(10);
}
}
3、当内部类在方法中时,内部类要访问外部类方法中的局部变量时,局部变量只能通过final修饰
当外部类的局部变量和内部类的局部变量相同时,该怎么获取这两个变量呢?
class Outer{
int a=2;
public class Inter{
int a=4;
public void print(){
System.out.println(this.a);
System.out.println(Outer.this.a);
}
}
}
public class Test{
public static void main(String[] args) {
Outer.Inter in=new Outer().new Inter();
in.print();
}
}
运行后的结果是:4 2
从结果可以看出在变量相同的情况下,要想调用Outer类中变量时,就需要使用Outer类对象的引用来调用当前的类中的变量。
匿名内部类 :
public class StudentTest{
public static void main(String[] args) {
new Person(){
public void sleep() {
System.out.println("匿名内部类");
}
}.sleep();
}
}
interface Person{
abstract void sleep();
}
运行结果:匿名内部类
上面main方法中就是一个匿名内部类,因为Person类是抽象的,必须子类去实现其中的抽象方法,通过子类的对象调用方法。定义匿名内部类的前提是内部类必须是继承一个类或者实现接口。
单例设计模式:
单例设计模式的特点是一个类实现了该模式那么在内存中该类只存在一个对象。
要想成功得设计出单例设计模式必须符合以下几点:
1、构造方法私有化,即该方法要被private修饰。原因:不能使其他程序实例化该类对象。
2、在类内部设计一个私有化且静态的该类实例对象,是为了让其他程序使用这个对象。
3、要想使其他程序获得这个对象,在该类中设计一个公开静态的方法。因为其他程序不能new出对象,只能通过方法获取对象,用类名.方法名调用,所以方法必须是静态的。
如下程序:
public class SingleTest{
public static void main(String[] args) {
//Single s=new Single(); 编译报错,构造方法被私有化不能new出对象。
Single.getInstance().print();
}
}
class Single{
private static Single s=new Single();
private Single(){
}
public static Single getInstance(){
return s;
}
public void print(){
System.out.println("单例设计模式");
}
}
多态:
多态意味着一个对象可以多重特征,可以在特定的情况下,表现出不同的状态。
public class Test{
public static void main(String[] args) {
Dog dag=new Dog();
AnimalTest(dag);
Cat cat=new Cat();
AnimalTest(cat);
}
public static void AnimalTest(Animal animal){
animal.eat();
}
}
abstract class Animal{
public abstract void eat();
}
class Dog extends Animal{
public void eat() {
System.out.println("吃骨头");
}
}
class Cat extends Animal{
public void eat(){
System.out.println("吃鱼");
}
}
总结:
多态的体现:1、父类的引用指向了子类的对象 2、父类的引用也可以接收自己的子类对象
多态的前提:必须类与类之间有关系,要么继承要么实现。
多态的好处:提高了程序的扩展性。