首页 / JAVA / 《Java核心技术》:面向对象
《Java核心技术》:面向对象
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了《Java核心技术》:面向对象,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含19865字,纯文字阅读大概需要29分钟。
内容图文
面向过程(Procedure Oriented)
面向对象(Object Oriented)
面向对象编程(Object Oriented Programming),是一种通过对象的方式,把现实世界映射到计算机模型的一种编程方法。
一、类与对象
类(Class):是对一类事物的描述 ,是抽象的 、概念上的定义,由属性(Field)、方法(Method)和构造方法(Constructor )组成。
对象(Object):是实际存在的该类事物的每个个体,因而也称为实例(instance)。
如:“书”是一种抽象的概念,它是类,而《Java核心技术》、《Java编程思想》是对象。
1.1 定义类
定义类语法:
修饰符 class 类名 {
属性声明;
方法声明;
}
/**
* 测试定义类
* @author 林
*
*/
public class TestStudent {
String name; //属性声明
int age;
public void study() { //方法声明
System.out.println("学习中");
}
}
1.2 创建对象
创建对象语法:
类名 变量名=new 类构造方法;
// 测试创建对象,TestStudent()是类TestStudent的构造方法
TestStudent s=new TestStudent();
1.3 属性
属性(Field):用于定义该类或该类对象包含的数据或者说静态特征。属性作用范围是整个类体。
属性也叫成员变量、作用域。
属性语法:
[修饰符] 属性类型 属性名 = [默认值] ;
属性默认初始值:
数据类型 | 初始化默认值 |
---|---|
整型 | 0 |
浮点型 | 0.0 |
字符型 | 0或'\u0000' |
布尔型 | false |
所有引用类型 | null |
Java 语言中除基本类型之外的变量类型都称之为引用类型。
1.4 修饰符
同一个类 | 同一个包 | 子类 | 所有类 | |
---|---|---|---|---|
private | √ | × | × | × |
default(默认) | √ | √ | × | × |
protected | √ | √ | √ | × |
public | √ | √ | √ | √ |
1.5、内存分析
栈( Stack):存储局部变量。
堆( Heap):存储对象实例。
方法区(Method Area) :存储类信息(Class对象)、 字符串常量、 静态变量、 静态方法。
class Computer {
String brand; //品牌
}
public class SxtStu {
// field
int id;
String sname;
int age;
Computer comp;
void study() {
System.out.println("我正在学习!使用我们的电脑,"+comp.brand);
}
SxtStu() {
}
public static void main(String[] args) {
SxtStu stu1 = new SxtStu();
stu1.sname = "张三";
Computer comp1 = new Computer();
comp1.brand = "联想";
stu1.comp = comp1;
stu1.study();
}
}
二、方法
方法用于定义该类或该类实例的行为特征和功能实现。
方法是从属于类和对象的。
语法:
修饰符 方法返回类型 方法名(方法参数列表) {
若干方法语句;
return 方法返回值;
}
2.1 构造方法
构造器也叫构造方法(constructor),用于对象的初始化。
构造方法是一个创建对象时被自动调用的特殊方法,目的是对象的初始化。
【构造方法要点】:
-
通过new关键字调用。
-
构造方法有返回值,但不能定义返回值类型,不能在构造器里使用return返回某个值。
-
如没有定义构造方法,则编译器会自动定义一个无参的构造方法。如已定义则编译器不会自动添加。
-
构造器的方法名必须和类名一致。
package com.test.java;
/**
* 测试自定义构造方法
* @author 林
*
*/
public class TestStu {
public static void main(String[] args) {
Stu s=new Stu("林一",17); // 调用构造方法创建对象
System.out.println(s.getName());
}
}
class Stu{
private String name;
private int age;
public Stu(String name,int age) { //自定义构造方法
this.name=name;
this.age=age;
}
public String getName() {
return this.name;
}
public int getAge() {
return this.age;
}
}
如一个类没有定义构造方法,编译器会自动为我们生成一个无参构造方法,它没有执行语句。
如自定义了一个构造方法,那么,编译器就不再自动创建无参构造方法。
构造方法可以重载。
如构造方法中形参名与属性名相同时,需要使用this关键字区分属性与形参。
/* 测试构造方法重载 */
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name; // this.name 为类属性
this.age = age;
}
public Person(String name) {
this.name = name;
this.age = 12;
}
public Person() {
}
}
2.2 方法参数
class Group {
String[] names;
public void setNames(String... names) { // String... 为可变参数
this.names = names;
}
}
// 测试可变参数传递
Group g=new Group();
g.setNames(); //传0个参数
g.setNames("林一"); //传1个参数
g.setNames("林一","林二"); //传2个参数
基本数据类型参数的传值:传递的是值的副本,副本改变不会影响原件。
// 测试基本类型参数传递
public class Main {
public static void main(String[] args) {
Person p = new Person();
int n = 15;
p.setAge(n); //setAge()方法获得的参数,复制了n的值给p.age,后面n改变不影响p.age
System.out.println(p.getAge()); // 打印15
n = 20;
System.out.println(p.getAge()); // 打印15
}
}
引用类型参数的传递:传递的是对象地址。
// 测试引用类型参数的传递
public class TestMethod {
public static void main(String[] args) {
Person p=new Person();
String[] f=new String[] {"林一","林二"};
p.setName(f); //数组是一个对象,传入数组只是传引用地址
System.out.println(p.getName());
f[1]="林三"; //修改数组元素
System.out.println(p.getName()); //引用地址没变,数组元素改变,结果也改变
}
}
class Person{
private String[] name;
public String getName() {
return this.name[0]+" "+this.name[1];
}
public void setName(String[] name) {
this.name=name;
}
}
2.3 方法重载
(Overload)
方法名相同,但各自的参数不同,称为方法重载。
注意:方法重载的返回值类型通常都是相同的。
方法重载的目的是,功能类似的方法使用同一名字,更容易记住,因此,调用起来更简单。
2.4 equals方法
Object 的 equals 方法默认就是比较两个对象的hashcode,是同一个对象的引用时返回 true 否则返回 false。
“==”代表比较双方是否相同。如果是基本类型则表示值相等,如果是引用类型则表示地址相等即是同一个对象。
判断2个字符串值是否相同,使用equals 方法。
package com.test.java;
/**
* 测试Equals与== 差异
* @author 林
*
*/
public class TestEquals {
public static void main(String[] args) {
String s1=new String("林一");
String s2=new String("林一");
System.out.println(s1==s2); //false, 两个字符串不是同一个对象
System.out.println(s1.equals(s2)); //true, 两个字符串内容相同
}
}
2.5 toString方法
Object类中定义有public String toString()方法,其返回值是 String 类型。
在打印输出或者用字符串连接对象时,会自动调用该对象的toString()方法。
package com.test.java;
/**
* 测试toString默认输出值
* @author 林
*
*/
public class TestToString {
public static void main(String[] args) {
Per p=new Per();
System.out.println(p); //自动调用该对象的toString()
}
}
class Per{
String name;
int age;
}
com.test.Per@15db9742
package com.test.java;
/**
* 测试重写toString方法
* @author 林
*
*/
public class TestToString {
public static void main(String[] args) {
Per p=new Per();
p.name="林一";
p.age=18;
System.out.println(p);
}
}
class Per{
String name;
int age;
@Override
public String toString() { //重写toString方法
return name+" "+age;
}
}
林一 18
三、关键字
3.1 this关键字
this的本质就是“创建好的对象的地址”。方法中使用this代表“当前对象” 。如没有命名冲突,可以省略this
。
this最常的用法:
- 普通方法中,this总是指向调用该方法的对象。构造方法中,this总是指向正要初始化的对象。
- 使用this关键字调用重载的构造方法,避免相同的初始化代码,且必须位于构造方法的第一句。
- this不能用于static方法中。
class Person {
private String name;
public void setName(String name) {
this.name = name; // this.name为成员变量
}
}
public class TestThis {
int a;
int b;
int c;
TestThis(){}
TestThis(int a,int b){
this.a=a;
this.b=b;
}
TestThis(int a,int b,int c){
this(a,b); //调用带参的构造方法,并且必须位于第一行
this.c=c;
}
}
3.2 super关键字
super是直接父类对象的引用。可以通过super来访问父类中被子类覆盖的方法或属性。
构造方法如使用super语句,需放在第一行。
class Student extends Person {
public String hello() {
return "Hello, " + super.name; //调用父类属性
}
}
class Student extends Person {
protected int score;
public Student(String name, int age, int score) {
super(name, age); // 调用父类的构造方法Person(String, int)
this.score = score;
}
}
3.3 static关键字
static声明的成员变量为静态成员变量,也称为类变量。
类变量的生命周期和类相同,在整个应用程序执行期间都有效。
- 为该类的公用变量,属于类,被该类的所有实例共享,在类被载入时被显式初始化。
- 对于该类的所有对象来说,static成员变量只有一份。被该类的所有对象共享。
- 一般用“类名.类属性/方法”来调用。
- 在static方法中不可直接访问非static的成员
static修饰的成员变量和方法,从属于类。
普通变量和方法从属于对象的。
/**
* 测试static关键字
* @author 林
*
*/
public class TestStatic {
int a;
static int width; //静态成员变量、类属性
static void gg() { //静态方法
System.out.println("gg");
}
void tt() { //普通方法
System.out.println("tt");
}
public static void main(String[] args) { //java程序执行入口
TestStatic hi=new TestStatic();
TestStatic.width=2; //调用静态成员变量
TestStatic.gg(); //调用静态方法
}
}
静态初始化块,用于类的初始化操作。
/**
* 测试静态初始化块
* @author 海
*
*/
public class TestStaticBlock {
static { //静态初始化块,类载入时加载
System.out.println("静态初始化块");
}
public static void main(String[] args) {
System.out.println("main方法");
}
}
3.4 final关键字
final作用:
-
修饰变量: 被他修饰的变量不可改变(变量名大写)。一旦赋了初值,就不能被重新赋值。
-
修饰方法:该方法不可被子类重写。但是可以被重载。
-
修饰类: 修饰的类不能被继承。比如:Math、String等。
final int MAX_SPEED = 120; // 修饰变量
final void study(){}; //修饰方法
final class A {} //修饰类
四、包(package)
包机制是Java中管理类的重要手段,通过包我们很容易对解决类重名的问题,也可以实现对类的有效管理。
【二个要点】:
-
通常是类的第一句非注释性语句。
-
包名:域名倒着写即可,再加上模块名,便于内部管理类。
package com.test.java;
public class TestPerson {
}
4.1、常用包
包名 | 说明 |
---|---|
java.lang | 包含一些Java语言的核心类,如String、Math、Integer、System和Thread,提供常用功能。 |
java.awt | 包含了构成抽象窗口工具集(abstract window toolkits)的多个类,这些类被用来构建和管理应用程序的图形用户界面(GUI)。 |
java.net | 包含执行与网络相关的操作的类。 |
java.io | 包含能提供多种输入/输出功能的类。 |
java.util | 包含一些实用工具类,如定义系统特性、使用与日期日历相关的函数。 |
4.2 导入类
【要点】:
-
Java会默认导入java.lang包下所有的类,因此这些类我们可以直接使用。
-
如果导入两个同名的类,只能用包名+类名来显示调用相关类。
import java.sql.Date;
import java.util.*;
4.3 静态导入
静态导入:其作用是用于导入指定类的静态属性,这样可以直接使用静态属性。
package com.test.java;
/**
* 测试静态属性导入的使用
* @author 海
*
*/
import static java.lang.Math.*; //导入Math类的所有静态属性
import static java.lang.Math.PI;
public class Test {
public static void main(String[] args) {
System.out.println(PI);
System.out.println(random());
}
}
六、继承
Java使用extends关键字来实现继承。
- 子类继承父类,可得到父类的全部属性和方法 (除了父类的构造方法),但父类私有的属性和方法不可以直接访问。
- 子类不会继承任何父类的构造方法。子类默认的构造方法是编译器自动生成的,不是继承的。
Object类是所有Java类的根基类。
package com.test.java;
/**
* 测试继承
* @author 林
*
*/
class Person {
private String name;
private int age;
public String getName() {...}
public void setName(String name) {...}
public int getAge() {...}
public void setAge(int age) {...}
}
class Student extends Person { // 继承父类的属性和方法
private int score;
public int getScore() { … }
public void setScore(int score) { … }
}
6.1 方法重写
方法重写(override):子类通过重写父类的方法,可以用自身的行为替换父类的行为。
方法的重写是实现多态的必要条件。
package com.test.java;
/**
* 测试方法重写Override
* @author 林
*
*/
public class TestOverride {
public static void main(String[] args) {
Vehicle v=new Vehicle();
Vehicle p=new Plane();
v.run();
p.run();
}
}
class Vehicle{ //交通工具类
public void run() {
System.out.println("交通工具运行");
}
}
class Plane extends Vehicle{
@Override
public void run() { //重写父类方法
System.out.println("飞机天上飞");
}
}
6.2 继承树追溯
构造方法第一句总是:super(…)来调用父类对应的构造方法。
流程就是:先向上追溯到Object,然后再依次向下执行类的初始化块和构造方法,直到当前子类为止。
package com.test.java;
/**
* 测试super
* @author 林
*
*/
public class TestSuper {
public static void main(String[] args) {
System.out.println("创建Class");
new ChildClass();
}
}
class FatherClass{
public FatherClass() {
System.out.println("创建FatherClass");
}
}
class ChildClass extends FatherClass{
public ChildClass() {
System.out.println("创建ChildClass");
}
}
创建Class
创建FatherClass
创建ChildClass
七、封装
Java中4种“访问控制符”分别为private、default、protected、public,可以修饰属性和方法。
Java封装就是隐藏细节,提供对外API接口。
封装的使用细节:
-
一般使用private访问权限。
-
提供相应的get/set方法来访问相关属性,这些方法通常是public修饰的,以提供对属性的赋值与读取操作。(注意:boolean变量的get方法是is开头!)
-
一些只用于本类的辅助性方法可以用private修饰,希望其他类调用的方法用public修饰
package com.test.java;
/**
* 测试封装
* @author 林
*
*/
public class TestFZ {
public static void main(String[] args) {
Stu s1=new Stu("林一",18);
System.out.println(s1);
Stu s2=new Stu("林二",-11);
System.out.println(s2);
}
}
class Stu{
private String name;
private int age;
private boolean flag;
public Stu(String name,int age) { //构造方法
this.name=name;
setAge(age);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if(age<0) { //在赋值之前先判断年龄是否合法
System.out.println("输入年龄错误。");
}else {
this.age = age;
}
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
@Override
public String toString() {
return getName()+" "+getAge();
}
}
八、多态
多态指的是同一个方法调用,由于对象不同可能会有不同的行为。
多态的要点:
-
多态是方法的多态,不是属性的多态。
-
多态的存在要有3个必要条件:继承,方法重写,父类引用指向子类对象。
-
父类引用指向子类对象后,用该父类引用调用子类重写的方法,此时多态就出现了。
package com.test。java;
/**
* 测试多态
* @author 林
*
*/
public class TestPolym {
public static void main(String[] args) {
Animal a1=new Dog(); //父类引用指向子类对象,向上可以自动转型
Animal a2=new Cat();
animalCry(a1); //传的具体是哪一个类就调用哪一个类的方法。
animalCry(a2);
Dog d1=(Dog)a1; //向下需要强制类型转换
d1.seeDoor();
}
/* 有了多态,只需要让增加的这个类继承Animal类就可以了 */
static void animalCry(Animal a) {
a.shout();
}
}
class Animal{
public void shout() {
System.out.println("叫了一声");
}
}
class Dog extends Animal{
public void shout() { //重写父类方法
System.out.println("汪汪汪");
}
public void seeDoor() {
System.out.println("看门");
}
}
class Cat extends Animal{
public void shout() {
System.out.println("喵喵喵");
}
}
九、抽象方法和抽象类
抽象方法:使用abstract修饰的方法,没有方法体,只有声明。通过abstract方法定义规范,然后要求子类必须定义具体实现。
抽象类:包含抽象方法的类就是抽象类。
抽象类使用要点:
-
有抽象方法的类只能定义成抽象类。
-
抽象类不能实例化,即不能用new来实例化抽象类。
-
抽象类可以包含属性、方法、构造方法。但是构造方法不能用来new实例,只能用来被子类调用。
-
抽象类只能用来被继承。
-
抽象方法必须被子类实现。
package com.test;
/**
* 测试抽象类与方法
* @author 林
*
*/
public class TestAbs {
public static void main(String[] args) {
Dog d=new Dog();
d.shout();
}
}
abstract class Animal{ //抽象类
abstract public void shout(); //抽象方法
}
class Dog extends Animal{
public void shout() { //子类必须实现父类的抽象方法,否则编译错误
System.out.println("汪汪汪");
}
}
十、接口
接口就是比“抽象类”还“抽象”的“抽象类”,可以更加规范的对子类进行约束。
10.1 接口定义
语法:
[访问修饰符] interface 接口名 [extends 父接口1,父接口2…] {
常量定义;
方法定义;
}
访问修饰符:只能是public或默认。
接口名:和类名采用相同命名机制。
extends:接口可以多继承。
常量:接口中的属性只能是常量,总是:public static final 修饰。不写也是。
方法:接口中的方法只能是:public abstract。 省略的话,也是public abstract。
接口要点:
- 子类通过implements来实现接口中的规范。
- 接口不能创建实例,但是可用于声明引用变量类型。
- 一个类实现了接口,必须实现接口中所有的方法,并且这些方法只能是public的。
package com.test.java;
/**
* 测试接口类
* @author 林
*
*/
public class TestInterface {
public static void main(String[] args) {
Traffic t1=new Car(); //创建Car()对象
t1.run();
System.out.println(t1.SPEED);
}
}
interface Traffic{ //交通接口
int SPEED=100; //总是:public static final类型的;
void run(); //总是:public abstract void run();
}
class Car implements Traffic{ //car类实现Traffic接口
public void run() {
System.out.println("汽车在跑");
}
}
class Train implements Traffic{
public void run() {
System.out.println("火车在跑");
}
}
10.2 接口多继承
接口完全支持多继承。和类的继承类似,子接口扩展某个父接口,将会获得父接口中所定义的一切。
interface A {
void testa();
}
interface B {
void testb();
}
interface C extends A, B { //接口C继承接口A和B
void testc();
}
public class Test implements C {
public void testc() {}
public void testa() {}
public void testb() {}
}
十一、内部类
把一个类放在另一个类的内部定义,称为内部类(innerclasses)。
内部类的作用:
1. 内部类提供了更好的封装。只能让外部类直接访问,不允许同一个包中的其他类直接访问。
2. 内部类可以直接访问外部类的私有属性,内部类被当成其外部类的成员。 但外部类不能访问内部类的内部属性。
3. 接口只是解决了多重继承的部分问题,而内部类使得多重继承的解决方案变得更加完整。
class Outer { // 外部类
private int age = 10;
public void show(){
System.out.println(age);//10
}
public class Inner { // 内部类
private int age = 20;
public void show(){
System.out.println(age);
}
}
}
11.1 成员内部类
package com.test.java;
/**
* 测试非静态成员内部类
* @author 林
*
*/
public class TestInnerClass {
public static void main(String[] args) {
Outer.Inner i=new Outer().new Inner(); //非静态成员内部类创建对象
i.show();
}
}
class Outer {
private int age=10;
class Inner{ // 非静态成员内部类
int age=20;
public void show() {
int age=30;
System.out.println("内部类方法里的局部变量:"+age);
System.out.println("内部类的成员变量:"+this.age);
System.out.println("外部类的成员变量:"+Outer.this.age);
}
}
}
内部类方法里的局部变量:30
内部类的成员变量:20
外部类的成员变量:10
package com.test.java;
/**
* 测试静态成员内部类
* @author 林
*
*/
public class TestInnerClass {
public static void main(String[] args) {
Outer.Inner i=new Outer.Inner(); //静态成员内部类创建对象
}
}
class Outer {
private int age=10;
static class Inner{ // 静态成员内部类,相当于外部类的一个静态成员
}
}
11.2 匿名内部类
匿名内部类:适合那种只需要使用一次的类。比如:键盘监听操作等等。
- 匿名内部类没有访问修饰符。
- 匿名内部类没有构造方法。
语法:
new 父类构造器(实参类表) \实现接口 () {
//匿名内部类类体!
}
this.addWindowListener(new WindowAdapter(){
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}
);
11.3 局部内部类
定义在方法内部的,作用域只限于本方法,称为局部内部类。
package com.test;
/**
* 测试局部内部类
* @author 林
*
*/
public class TestInnerClass {
public void show() {
class Inner{ //局部内部类
public void fun() {
System.out.println("Hello Java");
}
}
new Inner().fun();
}
public static void main(String[] args) {
new TestInnerClass().show();
}
}
11.4 String类
String类又称作不可变字符序列。
Java没有内置的字符串类型,而是在标准Java类库中提供了一个预定义的类String,每个用双引号括起来的字符串都是String类的一个实例。
String e = "" ; // 空字符串
String greeting = " Hello World ";
String s1 = "Hello";
String s2 = "World! ";
String s = s1 + s2; // Java允许使用符号"+"把两个字符串连接起来
// "+"运算符两侧的操作数中只要有一个是字符串(String)类型,系统会自动将另一个操作数转换为字符串然后再进行连接。
int age = 18;
String str = "age is" + age; //str赋值为"age is 18"
System.out.println("age is" + age);
String类常用方法:
String方法 | 描述 |
---|---|
s1.charAt(3) | 根据索引提取字符 |
s1.length() | 获取字符串长度 |
s1.equals(s2) | 比较两个字符串是否相等 |
s1.equalsIgnoreCase(s2) | 比较两个字符串是否相等(忽略大小写) |
s1.indexOf("Java") | 字符串s1中是否包含Java,如包含返回第一个字符的索引,不包含返回-1 |
s = s1.replace(' ', '&') | 将s1中的空格替换成& |
s1.startsWith("Hello") | 是否以Hello开头 |
s1.endsWith("Java") | 是否以Java结尾 |
s = s1.substring(4) | 提取子字符串:下标为4的开始到字符串结尾为止 |
s = s1.substring(4, 7) | 提取子字符串:下标[4, 7) 不包括7 |
s = s1.toLowerCase() | 转小写 |
s = s1.toUpperCase() | 转大写 |
s = s2.trim() | 去除字符串首尾的空格,中间的空格不能去除 |
/**
* 测试String常用方法
* @author 林
*
*/
public class TestString {
public static void main(String[] args) {
String s1="Hello Java";
String s2="Core Java";
String s3="core Java";
String s4=" Core ";
System.out.println(s1.charAt(4));
System.out.println(s1.length());
System.out.println(s2.equals(s3));
System.out.println(s2.equalsIgnoreCase(s3));
System.out.println(s1.indexOf("java"));
System.out.println(s1.replace(' ', '='));
System.out.println(s1.startsWith("Hello"));
System.out.println(s1.endsWith("Java"));
System.out.println(s1.substring(4));
System.out.println(s1.substring(4,7));
System.out.println(s1.toLowerCase());
System.out.println(s1.toUpperCase());
System.out.println(s4.trim());
}
}
11.5 常量池
常量池分类:
- 全局字符串常量池:在类加载完成后,存放的是字符串常量的引用值(在堆中生成字符串对象实例)。
- class常量池:在编译阶段,存放的是常量文本字符串、final常量等)和符号引用。
- 运行时常量池:在类加载完成之后,将每个class常量池中的符号引用值转存到运行时常量池中。
内容总结
以上是互联网集市为您收集整理的《Java核心技术》:面向对象全部内容,希望文章能够帮你解决《Java核心技术》:面向对象所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。