赞
踩
https://www.jianshu.com/p/7a5b0043b035
面向对象的思想概述
一、设计类、其实就是设计类的成员
二、类和对象的使用
三、如果创建了一个类的多个对象,则每个对象都独立的拥有一套类的属性。(非static的)
意味着: 如果我们修改了一个对象的属性a,则不会影响另外一个一个对象属性a的值。
# 例子 public class PersionTest { public static void main(String[] args) { //创建对象 Persion persion = new Persion(); //调用属性 对象.属性 persion.name = "张三"; persion.age = 18; System.out.println("姓名: " + persion.name + "年龄: " + persion.age); //调用方法 对象.方法 persion.eat(); persion.speak("中国话"); //创建第二个对象 Persion persion2 = new Persion(); System.out.println(persion2.name);//因为persion2对象并没有赋值所以是null //创建第三个对象 Persion persion3 = persion1; System.out.println(persion3.name);//将p1变量保存的对象地址值赋值给p3,导致p1和p3指向了对空间中的同一个对象 张三 persion3.name = "王五"; System.out.println(persion1.name); //p3里面改的值,p1里面也改了 } } class Persion{ //属性 String name; int age; //方法 public void eat(){ System.out.println("我正在吃饭"); } public void speak(String language){ System.out.println("我讲的是" + language); } }
四、对象的内存解析
根据上面的例子画图
p3已经不算是创建一个新的对象,相当于创建一个变量,p1赋值给了p3。两者都是使用同一个堆中的值。
属性(成员变量) vs 局部变量
相同点:
不同点:
在类中声明的位置不同
class user{
int age;
}
关于权限修饰符的不同
默认初始化的情况
属性: 类的属性,根据其类型,都有默认初始化值
整型(byte、short、int、long): 0
浮点型(float、double): 0.0
字符型(char): 0 或 ‘\u0000’
布尔型(boolean): false
引用类型: null
局部变量: 没有默认初始化值,意味着,我们在调用局部变量之前,一定要显示赋值。特别的: 形参在调用时,我们赋值即可。
在内存中加载的位置
方法: 描述类应该具有的功能。
自己定义的方法:
class User{
public void eat(){
System.out.println("我在吃饭");
}
public String getName(String name){
return name;
}
}
方法的声明
权限修饰符 返回值类型 方法名(形参列表){ //形参列表根据情况来定有还是没有
}
注意: static、final、abstract 来修饰的方法,后面再讲。
方法的说明
关于权限修饰符:
返回值类型: 有返回值 vs 无返回值
方法名: 属于标识符,遵循标识符的规则和规范, 起的名字尽量"见名知意“
形参列表: 可以声明0个, 1个,或者多个形参
方法体:
return关键字的使用:
方法的使用
public class Dict {
public static void main(String[] args) {
new DictTest().eat();//没有赋值一个变量名直接调用就是匿名对象
}
}
class DictTest{
public void eat(){
System.out.println("我正在吃饭");
}
定义
如果有两个方法的方法名相同,但参数不一致,那么可以说一个方法是另一个方法的重载。
具体说明如下:
“两同一不同”:
public class Load { public void getSum(int a){ } public void getSum(int a,int b){ } public void getSum(String a){ } public void getSum(String a,Double c){ } }
判断是否是重载
跟方法的权限修饰符、返回值类型、形参变量名、方法体都没有关系!
在通过对象调用方式时,如何确定某一个指定的方法
方法名 —> 参数列表
public class Load { public static void main(String[] args) { New a = new New(); a.getName("张三"); } } class New{ // public void getName(String name){ // // } public void getName(String ... name){ //需要遍历不遍历输出的值是地址值 for (int i=0; i<name.length; i++){ System.out.println(name[i]); } } // public void getName(String[] name){ // 相当于上面,二者相同 // } //可变性参数只能写在末尾 public void getName(int age,String ... name){ } //可变个数形参在方法的形参中,最多只能声明一个可变形参。 //多了否则会报错 // public void getName(String ... name,int ... age){ // // } }
封装概述
是指隐藏对象的属性和实现细节,仅对外提供公共访问方式,这里就会用到一个关键字是private,在后面的使用成员变量时候,不能直接调动,只能通过方法调用;
封装的优点
封装性的体现
一、我们将类的属性私有化(private),同时,提供公共的(public)方法来获取(getXxx)和设置(setXxx)此属性的值。
二、不对外暴露的私有的方法
三、单例模式(将构造器私有化)
四、如果不希望类在包外被调用,可以将类设置为缺省的。
一个标准案例的使用
public class AnimalTest { public static void main(String[] args) { Animal animal = new Animal(); animal.setName("大黄"); System.out.println(animal.getName()); } } class Animal{ private String name; private int age; private int leg;//腿 public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getLeg() { return leg; } public void setLeg(int leg) { this.leg = leg; } }
封装性体现,需要权限修饰符来配合
2.四种权限可以用来修饰类及类的内部结构: 属性、方法、构造器、内部类
3.具体的,4种权限都可以用来修饰类的内部结构: 属性、方法、构造器、内部类
3.1 修饰类的话,只能使用: 缺省、public 例如 class Dog{} public class Cat{}
总结封装性: Java提供了四种权限修饰符来修饰类及类的内部结构,体现类及类的内部结构在调用时的可见性的大小。
构造器的作用
# 创建类的对象: new + 构造器
Persion p = new Persion()
说明
# 修饰符公共的 有参构造器
public Persion(int age) {
this.age = age;
}
3.一个类中定义的多个构造器,彼此构成重载。
4.一旦我们定义了类的构造器之后,系统就不再提供默认的无参构造器
5.一个类中,至少会有一个构造器。可能是自己定义的,也可能是系统提供的。
public class Persion {
private String name;
public Persion() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
this关键字的使用
this修饰属性和方法
this理解为: 当前对象
在类的方法或者构造器中,我们可以使用"this.属性" 或"this.方法"的方式,调用当前对象属性或方法。但是,通常情况下,我们都选择省略"this."。特殊情况下,如果方法或构造器的形参和类的属性同名时,我们必须显示的使用"this.变量"的方式,表名此变量是属性,而非形参,例如:
# this指向的是属性age而非形参里面的age
public class Persion {
private String name;
public Persion(String name) {
this.name = name;
}
}
this调用构造器
package关键字的使用
补充: 同一个包下,不能命名同名的接口、类。
不同的包下,可以命名同名的接口、类。
import关键字的使用
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
一、在 Java 中通过 extends 关键字可以申明一个类是从另外一个类继承而来的,一般形式如下:
public class 父类 {
}
public class 子类 extends 父类 {
}
体现: 一旦子类继承父类之后,子类就获取了父类中声明的所有的属性和方法。
特别的,父类中声明为private的属性或方法,子类继承父类以后,仍然认为获取了父类中私有的结构。只是因为封装性的影响,使得子类不能直接调用父类的结构而已。
注意: 父类中私有的方法不可以直接调用了,只能在父类中定义一个公共的方法,内部调用私有方法,例如:
public void study(){
System.out.println("正在学习");
eat();
}
private void eat(){
System.out.println("正在吃饭");
}
二、子类继承父类以后,还可以声明自己特有的属性或方法: 实现功能的扩展
# 在继承父类的基础上扩展功能
public class Dog extends Animal {
public int age;
public void sleep(){
System.out.println("我在睡觉");
}
}
三、需要注意的是Java不支持多继承,但支持多重继承
四、
定义
在子类中可以根据需要对从父类中继承来的方法进行改造,也称为方法的 重置、覆盖。在程序执行时,子类的方法将覆盖父类的方法。
要求
注意:
子类与父类中同名同参数的方法必须同时声明为非static的(即为重写),或者同时声明为static的(不是重写),因为static方法是属于类的,子类无法覆盖父类中的方法。
应用
1.重写以后,当创建子类对象以后,通过子类对象调用子父类中同名同参数的方法时,实际执行的是子类重写父类的方法。
public class father { public void eat(){ System.out.println("我在吃饭"); } } public class son extends father { public void eat(){ System.out.println("儿子在吃饭"); } } public class familyTest { public static void main(String[] args) { son son = new son(); son.eat(); //调用的是子类重写过后的方法 儿子在吃饭 } }
super关键字的使用
代码案例:
class Animal{ String name = "动物"; int age; int id = 1001; public void eat(){ System.out.println("动物们在吃饭"); } } class Dog extends Animal{ String sex; int id = 1002; public void show(){ System.out.println(name);//因为子类和父类之间并没有同名的name属性,所以调用name可以省略super System.out.println(super.id);//通过super获取父类的id } public void eat(){ super.eat();//调用父类中的eat方法 //System.out.println("狗在吃饭"); } } public class SuperTest { public static void main(String[] args) { Dog dog = new Dog(); dog.show();//动物 1001 dog.eat();// 动物们在吃饭 } }
4.super调用构造器
super调用构造器理解: https://blog.csdn.net/qq_34115899/article/details/80325079
理解多态性: 可以理解为一个事物的多种形态。
何为多态性:
对象的多态性: 父类的引用指向子类的对象(或子类的对象赋给父类的引用)
# 例子 Persion是父类,Man是子类。
Persion s1 = new Man();
多态的使用: 虚拟方法调用
对象的多态性,只适用于方法,不适用于属性。
# 示例
class Persion{
int id = 1001;
}
class Man extends Persion{
int id = 1002;
}
public class PersionTest {
public static void main(String[] args) {
Persion p = new Man();
System.out.println(p.id); //父类的1001
}
}
使用情景: 为了避免在向下转型时出现ClassCastException异常,我们在向下转型之前,先进行instanceof的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型。
public class PersionTest { public static void main(String[] args) { Persion p = new Man(); Persion p1 = new Woman(); // p.play(); //想使用子类里面的其它方法需要向下转型,使用instanceof进行判断 //p1 new的对象是Woman,也只能调用Woman里面的方法 //注意: 不能用p1 new Woman对象,来判断向下转型Man if (p1 instanceof Woman){ Woman woman = (Woman)p1; woman.eat(); } if (p instanceof Man){ Man man = (Man)p; //向下转型 man.eat(); } } }
Object类是所有Java类的根父类
如果在类的声明中未使用extedns关键字指明其父类,则默认父类为java.lang.Object类
public class Persion{
}
//等价于
public class Persion extends Object{
}
是一个方法,而非运算符
只能适用于引用数据类型
Object类中equals()的定义
public boolean equals(Object obj){
return(this == obj);
}
说明: Object类中定义的equals()的作用是,比较两个对象的地址值是否相同。和==相同。
像String、Date、File、包装类等都重写了Object类中equals()方法。重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象的"实体内容"是否相同。
通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的"实体内容"是否相同。那么,我们就需要对Object类中的equals()进行重写。
class Man{ String name; int age; public Man(String name, int age) { this.name = name; this.age = age; } //手动重写equals (开发建议使用开发工具自动生成的equals) @Override public boolean equals(Object o) { if (this == o){ return true; } if (o instanceof Man){ Man man = (Man)o; return this.age == man.age && this.name.equals(man.name); }else { return false; } } } public class PersionTest { public static void main(String[] args) { Man man = new Man("王五",20); Man man1 = new Man("王五",20); System.out.println(man.equals(man1)); } }
6.重写equals(方法的原则
当我们输出一个对象的引用时,实际上就是调用当前对象的toString( )
Object类中的toString()的定义
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
像String、Date、File、包装类都重写了Object类中的toString()方法,使得在调用对象的 toString()时,返回"实体内容"信息。
自定义类重写toString()方法
class Man{ String name; int age; @Override public String toString() { return "Man{" + "name='" + name + '\'' + ", age=" + age + '}'; } } public class PersionTest { public static void main(String[] args) { Man man = new Man();' //调用的就是重写之后的toString()方法而不是Object里面的toString()方法了 System.out.println(man.toString()); } }
步骤
导入Junit4包 (推荐Maven导入方式)
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
创建Java类,进行单元测试。
此类中声明单元测试方法
此单元测试方法上需要声明注释 @Test,并在单元测试类中导入包: import org.junit.Test;
package Excel;
import org.junit.Test;
public class PersionTest {
@Test
public void test(){
int a = 0;
System.out.println(a);
}
}
好处
基本数据类型 | 包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
boolean | Boolean |
char | Character |
包装类的使用:
public class WapperTest { //基本数据类型 -- >包装类;调用包装类的构造器 @Test public void test1(){ int num = 10; int num2 = 10; Integer integer = new Integer(num); Integer integer1 = new Integer(num2); System.out.println(integer.toString()); System.out.println(integer.equals(integer));//包装了重写equals方法比较的是内容了 } //包装类 --->基本数据类型:调用包装类的xxxValue() @Test public void test2(){ Integer integer = new Integer(1); int num = integer.intValue(); System.out.println(integer); } //JDK 5.0新特性: @Test public void test3(){ //自动装箱 int num = 10; Integer integer = num; System.out.println(integer); //自动拆箱 Integer integer1 = new Integer(20); int num2 = integer1; System.out.println(num2); } //基本数据类型、包装类 --- >String类型,调用String重载的valueOf() @Test public void test4(){ int num = 10; String s = String.valueOf(num); System.out.println(s); String s1 = String.valueOf(new Integer(20)); System.out.println(s1); } //String类型 ---> 基本数据类型、包装类 @Test public void test5(){ String s = "123"; int i = Integer.parseInt(s); System.out.println(i); } }
static: 静态的
static可以用来修饰: 属性、方法、代码块、内部类
使用static修饰属性: 静态变量 或者称为(类变量)
属性:按是否使用static修饰,又分为: 静态属性 vs 非静态属性(实例变量)
static修饰属性的其他说明
静态变量随着类的加载而加载。可以通过"类.静态变量"的方式进行调用
静态变量的加载要早于对象的创建
由于类只会加载一次,则静态变量在内存中也只会存在一份: 存在方法区的静态域中。
例子
public class ChineseTest {
public static void main(String[] args) {
Chinese chinese = new Chinese();
Chinese chinese1 = new Chinese();
chinese1.name="法国";
System.out.println(Chinese.name);//通过类名.静态变量名调用 法国
System.out.println(chinese.name);//法国
System.out.println(chinese1.name);//法国 当静态变量值被修改,那么所有对象的值都会被修改,因为被static修饰的变量是共享的。
}
}
class Chinese{
//静态变量
static String name = "中国";
}
使用static修饰方法: 静态方法
随着类的加载而记载,可以通过"类.静态方法"的方式进行调用
例子
public class ChineseTest {
public static void main(String[] args) {
Chinese.eat();
}
}
class Chinese{
//静态方法
public static void eat(){
System.out.println("中国人吃中餐");
}
}
静态方法中,只能调用静态的方法或属性,例子:
非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性,例子:
static注意点:
开发中,如何确定一个属性是否要声明static
代码块的作用: 用来初始化类、对象
代码块如果有修饰的话,只能使用static
分类: 静态代码块和非静态代码块
静态代码块
内部可以有输出语句
随着类的加载而执行,只执行一次
调用类的静态方法加载静态的代码块,只执行一次。
static {
System.out.println("我是静态代码块");
}
作用: 初始化类的信息,例如被static修饰的属性、方法。
如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
静态代码块的执行要优先于非静态代码块的执行
静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构
非静态代码块
内部可以有输出语句
随着对象的创建而执行,每创建一个对象,就会执行一次非静态代码块。
创建完对象才会加载非静态代码块,并且每造一个对象,都会加载一次非静态代码块
{
System.out.println("我是非静态代码块");
}
作用: 可以在创建对象时,对对象的属性或方法等进行初始化。
如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行。
非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法。
被修饰的类不能被其它类所继承
比如: String类、System类、StringBuffer类,源代码中已经被final修饰了。
被修饰的方法不能被重写
比如: Object类中的getClass();
abstract关键字的使用
public class AbstractTest { public static void main(String[] args) { Student student = new Student(); student.eat(); } } abstract class Persion{ String name; int age; public Persion() { } public Persion(String name, int age) { this.name = name; this.age = age; } public abstract void eat(); } class Student extends Persion{ @Override public void eat() { System.out.println("学生要吃有营养的饭"); } }
接口的使用
接口使用interface来定义
Java中,接口和类是并列的两个结构,(同级别)
如何定义接口: 定义接口中的成员
JDK7及以前: 只能定义全局常量和抽象方法
JDK8: 除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法(新特性)。
接口中定义的静态方法,只能通过接口来调用。也就是(接口名.方法名)。
通过实现类的的对象,可以调用接口中的默认方法。
如果实现类重写了接口的默认方法,调用时,仍然调用的是重写以后的方法。
如果子类继承父类和实现的接口中声明了同名同参数的方法,那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法。
子类的方法中调用接口中的默认方法,格式: 接口名.super.方法名
例子 public class InterfaceTest2 { public static void main(String[] args) { Animal.eat();//动物们要吃好吃的 new Cat().play();//狗在玩游戏 new Cat().run();//狗在跑步 new Cat().sleep(); } } interface Animal{ //静态方法 public static void eat() { System.out.println("动物们要吃好吃的"); } //默认方法 public default void play(){ System.out.println("动物们正在玩游戏"); } public default void run(){ System.out.println("动物们在跑步"); } public default void gram(){ System.out.println("动物们在玩游戏"); } } class Dog{ public void run(){ System.out.println("狗在跑步"); } } class Cat extends Dog implements Animal{ //重写之后的方法 public void play(){ System.out.println("猫在玩游戏"); } public void sleep(){ System.out.println("狗在睡觉"); //调用接口中的方法 Animal.super.gram(); } }
接口中不能定义构造器,意味着接口不可以实例化。
Java开发中,接口通过让类去实现(implements)的方式来使用
如果实现类覆盖了接口中的所有的抽象方法,则此实现类就可以实例化
如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类
简单明了,如果一个类想使用一个接口,那么必须要重写接口里面的抽象方法。
例子 public class InterfaceTest { public static void main(String[] args) { Cat cat = new Cat(); System.out.println(cat.mode); cat.eat(); } } interface Fly{ String mode = "老虎"; //省写了 public static final void eat();//省写了 public abstract } class Cat implements Fly{ @Override public void eat() { System.out.println("猫吃猫粮"); } }
Java类可以实现多个接口 -->弥补了Java单继承的局限性
格式一 class A extends B implements C,D
class Kit{
}
interface Wrench{
}
interface Insertion{
}
class Comprehensive extends Kit implements Wrench,Insertion{
}
格式二 class A implements B,C
interface Wrench{
}
interface Insertion{
}
class Comprehensive implements Wrench,Insertion{
}
接口与接口之间可以继承,而且可以多继承
interface Car{
}
interface Bike{
}
interface Foot extends Car,Bike{
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。