目录
一.数据类型和输出
public class Test {
public static void main(String[] args) {
System.out.println("hello");
System.out.println("hello2");
int a;
a = 10;
int b = 20;
System.out.println("a="+a);
//printf("a=%d",a);
System.out.println("b="+b);
//printf("b=%d",b);
int c;
c = 30;
System.out.println("a="+a + "b="+b + "c="+c);
//printf("a=%db=%dc=%d",a,b,c);
System.out.println(a + "+" +b +"=" +c);
//printf("%d+%d=%d",a,b,c);
float f = (float)0.1; //java会默认把小数定为double类型
double d = 0.2;
System.out.println("f="+f);
System.out.println("d="+d);
}
}
二.控制流程
public class Test {
public static void main(String[] args) {
int a = 1;
if(a>0){
System.out.println("a是正整数");
if(a == 1){
System.out.println("它是正整数且是1");
}else{
System.out.println("它是正整数不是1");
}
}else{
System.out.println("a是负整数");
}
switch(a){
case 1:
System.out.println("这是1");
break;
case 2:
System.out.println("这是2");
break;
case 3:
System.out.println("这是3");
break;
}
}
}
三.循环
public class Test {
public static void main(String[] args) {
int i;
for(i=0;i<20;i++){
System.out.println("Hello World");
}
while(i >= 0){
System.out.println("你好");
i--;
}
}
}
四.数组
定义数组是尽量把[]放在数据类型声明后面,比如
int[] a;
public class Test {
public static void main(String[] args) {
int a[] = {1,2,3};
//java可以这样定义一个数组c这样定义的话后面要有确定的元素int b[];
System.out.println(a[0]);
System.out.println(a[1]);
System.out.println(a[2]);
//int a[3];
//int array[] = new int[3];
int array[] = null;
array = new int[3];
int i;
//array.length表示数组的长度
for(i=0;i<array.length;i++){
array[i] = i;
}
for(i=0;i<array.length;i++){
System.out.println(array[i]);
}
}
}
五.函数
要写在main外面
public class Test {
void myprint()
{
System.out.println("hello");
}
void putAInt(int a){
System.out.println("输出一个数:"+a);
}
public static void main(String[] args) {
//myprint();//如果要直接用需要在定义的时候加static
//putAInt(10);
Test t = new Test();//这里像用结构体里面的函数一样
t.myprint();
t.putAInt(10);
}
}
六.输入
import java.util.Scanner;//这个包放在JRE System Library->rt.jar->java.util->Scanner
public class Test {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);//有波浪线通过ctrl+shit+o
int a;
String str;
float f;
double d;
System.out.println("请输入一个整数");
a = sc.nextInt();
System.out.println("请输入字符串");
str = sc.nextLine();//跟c一样字符串需要吸收回车
str = sc.nextLine();
System.out.println("请输入一个小数");
f = sc.nextFloat();
System.out.println("请输入一个小数");
d = sc.nextDouble();
System.out.println("a="+a);
System.out.println("str:"+str);
System.out.println("f="+f);
System.out.println("d="+d);
}
}
七.封装类
一.概念
概念:定义类属性及其方法的过程称为封装类
属性:c语言-结构体里面的元素
方法:c语言-结构体里面的函数
class Student
{
private int age;
String name;
private int sex;
double score;
private void myage(int myage){
age = myage;
}
public int getage(){
myage(18);
return age;
}
public void realage(int realage)
{
age = realage;
}
void introduce(){
System.out.println("name="+name+",age="+age+",score="+score);
}
void testFunc(){
System.out.println("This is a test");
}
}
public class Test {
public static void main(String[] args) {
Student stu1 = new Student();//通过类实例化一个对象,new相当于开辟了一个空间
//类=模板
//类不能直接使用,不能直接访问变量,需要实例化,申请一个空间
//c语言:struct student *p;
//p = (struct student *)malloc(sizeof(struct student));
//使用这个类
//stu1.age = 18;
stu1.getage();
stu1.realage(36);
stu1.name = "Huang";
stu1.score = 87;
stu1.introduce();
stu1.testFunc();
}
}
public :该类或非该类均可访问
private :只有该类可以访问
protected :该类及其子类成员可以访问,同一个包的类也可以访问
默认 :同一个包中的类可以访问
位置 | private | 默认 | protected | public |
---|---|---|---|---|
同一个类 | 是 | 是 | 是 | 是 |
同一个包内的类 | 否 | 是 | 是 | 是 |
不同包内的子类 | 否 | 否 | 是 | 是 |
不同包并且不是子类 | 否 | 否 | 否 | 是 |
二.UML类图
Unified Modeling Language (UML)又称统一建模语言或者标准建模语言
类的命名尽量使应用领域中的术语明确、无歧义,以利于相互交流和理解。
类的属性、操作中的可见性使用+、#、- 分别表示public、protected、private。
三.构造方法
类构造方法的概念–(构造函数)
1.构造方法负责对象初始化工作,为对象的属性赋合适的初始值
2.创建对象时,其类的构造方法确保在用户操作对象之前,系统初始化的进行
构造方法的语法规则
1.构造方法名与类名一致
2.没有返回值–返回值为空不是void,是前面什么都没有
3.方法实现主要为字段赋初值
4.构造方法有重载性(就是可以有多个构造方法)
构造方法的调用
构造方法的调用很特别:new操作符(实例化对象的时候,自动被调用)
class Student
{
int age;
String name;
double score;
Student(){//java方法可以重载--函数名一样,参数列表不同;c不允许
System.out.println("第一个构造方法");//我们不写的话系统会默认有一个{}里面为空的构造方法
}
Student(int newage,String newname){
System.out.println("第二个构造方法");
age = newage;
name = newname;
}
Student(int newage,String newname,double newscore){
System.out.println("第三个构造方法");
age = newage;
name = newname;
score = newscore;
}
void introduce(){
System.out.println("name="+name+",age="+age+",score="+score);
}
}
public class Test {
public static void main(String[] args) {
Student stu1 = new Student();
stu1.introduce();
Student stu2 = new Student(15,"hello");
stu2.introduce();
Student stu3 = new Student(16,"world",98);
stu3.introduce();
}
}
代码结果
第一个构造方法
name=null,age=0,score=0.0
第二个构造方法
name=hello,age=15,score=0.0
第三个构造方法
name=world,age=16,score=98.0
四.关键字this的特点
1.在类的方法中,调用this代表调用此方法对象的引用
2.this可以看作一个变量,它的值是当前对象的引用
class Student
{
int age;
String name;
double score;
static int data;
Student(int newage,String name,double score){
System.out.println("这是构造方法");
this.age = newage;//注意看这里this.age是上面int age的引用
this.name = name;
this.score = score;
}
}
3.使用this处理方法中成员变量和形参同名的问题
4.在类的构造方法中可以调用this([参数列表])来调用该类的指定构造方法
class Student
{
int age;
String name;
double score;
void testThis(){//四.关键字this的特点
Student stuTmp = null;
stuTmp = this;
System.out.println(stuTmp.name);//2.this可以看作一个变量,它的值是当前对象的引用
System.out.println(this.name+" "+this.age);//1.在类的方法中,调用this代表调用此方法对象的引用
}
Student(){//java方法可以重载--函数名一样,参数列表不同;c不允许
System.out.println("第一个构造方法");//我们不写的话系统会默认有一个{}里面为空的构造方法
}
Student(int newage,String newname){
System.out.println("第二个构造方法");
age = newage;
name = newname;
}
Student(double score){//3.使用this处理方法中成员变量和形参同名的问题
this(21,"world");//4.在类的构造方法中可以调用this([参数列表])来调用该类的指定构造方法"只能用一个且在放在前面"
System.out.println("第三个构造方法");
//this.age = age;
//this.name = name;
this.score = score;
}
void introduce(){
System.out.println("name="+name+",age="+age+",score="+score);
}
}
public class Test {
public static void main(String[] args) {
Student stu1 = new Student(98.7);
stu1.introduce();
stu1.testThis();
}
}
五.static关键字
特点
1.用来修饰类的成员–被修饰的成员变量称为类变量(静态变量)
2.被修饰的成员方法称为类方法(静态方法)
3.当类被加载的时候就会被加载,优先于对象的存在
4.用来修饰语句块–称为静态代码块,先于构造方法之前执行,只会执行一次,用来对静态成员做初始化.
5.调用的时候可以直接通过类名.成员名来进行访问
注意
1.静态方法只能访问外部的静态成员
2.静态方法不能出现this关键字-原因是static先于构造方法之前执行,只会执行一次,用来对静态成员做初始化.-this有等用户输入的情况,所以不能带this
class Student
{
int age;
String name;
double score;
static int data;//1.类变量(静态变量)
Student(int age,String name,double score){//3.使用this处理方法中成员变量和形参同名的问题
System.out.println("这是构造方法");
this.age = age;
this.name = name;
this.score = score;
}
static{
System.out.println("这是静态代码块");//4.用来修饰语句块--称为**静态代码块**,先于构造方法之前执行,只会执行一次,用来对静态成员做初始化.
data = 50;
}
static void test(){
System.out.println(data);//1.静态方法只能访问外部的静态成员
//System.out.println(name);//1.静态方法只能访问外部的静态成员
//System.out.println(this.name);//2.静态方法不能出现this关键字
}
}
public class Test {
public static void main(String[] args) {
Student stu1 = new Student(18,"huang",98.7);
Student stu2 = new Student(18,"huang",98.7);//静态代码块只执行一次,静态代码块当类被加载的时候就会被加载
Student.data = 30;//5.调用的时候可以直接通过**类名.成员**名来进行访问
System.out.println("ret="+add(stu1.age,16));//3.当类被加载的时候就会被加载,优先于对象的存在
}
static int add(int a,int b){//2.被修饰的成员方法称为**类方法**(静态方法)
return a+b;
}
}
六.方法的重载
概念
概念:在同一个类中,同名不同参数的方法称为重载方法
注意:返回值不同的方法不能称为重载
多数程序设计语言要求为每个方法(函数)提供一个独一无二的方法名,不存在方法重载的概念
特点
在java中,规定方法签名是解析方法的规则而不是方法名,为方法重载创建了条件
方法重载使得在一个类中,方法名相同而参数列表不同的方法可同时存在,代表相似的行为或功能
例子
Java.io.PrintStream类的println方法能打印数据,根据数据类型不同有不同的实现方式
七.包
打包的意义:
1.标准java库是由一系列包组成,包括java.long java.util java.net等等.
2.标准java包就是层次包结构,就如同硬盘上的子目录一样,我们可以使用嵌套层次结构来组织包.
3.java包是为了更好规划代码,防止命名冲突和混乱,所以java出现了打包机制
4.当把类组织起来放进一个包内时,也就给包中的成员赋予了相应的访问权限,就拥有了该包内的程序代码
5.包访问权限把类聚集在一个包中这一做法提供了意义和理由
包Package–声明
1.java程序员都可以编写属于自己的java包,为了保证包名唯一性,要求程序员在定义自己包的名字前面加上唯一的前缀
2.由于互联网公司上的域名不会重复,所以推荐采用公司在互联网上的域名的倒置作为包的唯一前缀
包的调用
1.一个类可以使用同一个包中的所有类
2.一个类可以使用其他包中的所有公开类
3.怎么使用其它包中的公开类
1)在每个类签名加上完整报名,例如
java.util.Data today = new java.util.Date();
2)更简洁更通用的方式:使用import语句来导包(eclipse Ctrl+shift +o)
import java.util.Date;
…
Date today = new Date();
3)可以import特定类,也可以导入整个包,通过在源代码文件顶部(在打包语句后面)使用import语句来实现import java.util.*;
//import com.huang.use.code; import com.huang.use.*;
package com.huang.use;
public class code {
public int age;
public void printTest(){
System.out.println("age:"+this.age);
}
package com.huang.learn;
//import com.huang.use.code;
import com.huang.use.*;
public class Test {
public static void main(String[] args) {
com.huang.use.code abcd = new code();
abcd.age = 23;
abcd.printTest();
code abc = new code();
abc.age = 29;
abc.printTest();
}
}
八.类的继承
一.继承的概念
1.继承背后的思想就是基于已存在的类来构建新类
2.当从已存在的类继承时,就重用了它的方法和属性,还可以添加新的方法和属性来定制新类以应对需求
3.约定:从其他类导出的类叫子类。
被导出的类叫父类。
4.在java中,除了Object类之外,所有类都是子类,都只有唯一的父类
5.在java中,除了Object类之外,所有类都是子类,都只有唯一的父类
6.继承在OOP中不可或缺
7.创建一个类时,总是在继承
8.继承的意义
代码的重用
体现不同抽象层次
9.父子类关系
父类更抽象,更一般
子类更具体,更特殊
二.示例代码:
package com.first.java;
class Person{
String name;
String sex;
int age;
void printInfo(){
System.out.println("人吃饭");
}
}
class Student extends Person{
int score;
void studentInfo(){
System.out.println("学生吃饭");
System.out.println("名字:"+name+" 性别:"+sex+" 分数:"+score);
}
}
public class Test {
public static void main(String[] args) {
Student stu1 = new Student();
stu1.name = "张三";
stu1.sex = "男";
stu1.score = 89;
stu1.printInfo();
stu1.studentInfo();
}
}
三.跟继承有关的关键字Super
一.概念
1.super和this关键字的特点类似:super代表的是父类对象的引用
2.当父子类的成员出现同名时,可以通过super来区分
3.子类的构造方法中,通过super关键字调用父类的构造方法
二.范例代码
1.问题代码
package com.first.java;
class Person{
String name;
String sex;
int age;
void printInfo(){
System.out.println("人吃饭");
}
Person(String name,String sex){//默认有个一无参的构造方法,但是我们写了自己的构造方法后,默认的无参构造方法就没了,只能自己加无参构造方法才行
this.name = name;
this.sex = sex;
}
}
class Student extends Person{
int score;
void studentInfo(){
System.out.println("学生吃饭");
System.out.println("名字:"+name+" 性别:"+sex+" 分数:"+score);
}
}
public class Test {
public static void main(String[] args) {
Student stu1 = new Student();
stu1.name = "张三";
stu1.sex = "男";
stu1.score = 89;
stu1.printInfo();
stu1.studentInfo();
}
}
报错:
Implicit super constructor Person() is undefined for default constructor. Must define an explicit constructor
意思是:父类没有定义默认构造方法,必须定义明确的构造方法
2.解决方法一:
在父类添加一个无参构造方法
Person(){};
3.解决方法二:
在子类构造方法引用父类构造方法
Student(String name ,String sex){
super(name,sex);
}
4.最终代码:
package com.first.java;
class Person{
String name;
String sex;
int age;
void printInfo(){
System.out.println("人吃饭");
}
//Person(){};
Person(String name,String sex){//默认有个一无参的构造方法,但是我们写了自己的构造方法后,默认的无参构造方法就没了,只能自己加无参构造方法才行
this.name = name;
this.sex = sex;
}
}
class Student extends Person{
int score;
void studentInfo(){
System.out.println("学生吃饭");
System.out.println("名字:"+name+" 性别:"+sex+" 分数:"+score);
}
Student(String name ,String sex){
super(name,sex);
}
void printInfo(){
super.printInfo();//可以用super调用父类同名printInfo()
System.out.println("子类printInfo");
}
}
public class Test {
public static void main(String[] args) {
Student stu1 = new Student("李四","男");
//stu1.name = "张三";
//stu1.sex = "男";
stu1.score = 89;
stu1.printInfo();
stu1.studentInfo();
}
}
四.继承的私有权限
1.子类不能继承父类private的属性和方法
private String name;
导致出现的错误:
2.子类可以通过父类的构造方法、public的方法来处理private属性
Student(String name ,String sex){
super(name,sex);
}
五.继承后-方法的重写
一.什么是方法重写
方法重写是指子类可以根据需求,对从父类继承过来的方法进行重写
是多态机制的前奏
二.方法重写需要注意哪个方面
1.重写方法必须和被重写方法具有相同的方法名称、参数列表和返回值
2.重写方法的访问权限不能比被重写方法更严格
private void printInfo(){
//super.printInfo();//可以用super调用父类同名printInfo()
System.out.println("子类printInfo");
}
加上private后会提示:从父类继承的方法不能减少访问权限
3.父类的私有方法,不能被重写
4.在子类重写的方法中继续调用父类被重写的方法可以通过super. 函数名获得
三.方法重写和重载的区别
重载:只要方法名称相同就是重载
重写:必须和被重写方法具有相同的方法名称、参数列表和返回值
四.代码示例
package com.first.java;
class Person{
private String name;
String sex;
int age;
void printInfo(){
System.out.println("父类printInfo");
}
Person(String name,String sex){
this.name = name;
this.sex = sex;
}
}
class Student extends Person{
Student(String name ,String sex){
super(name,sex);
}
int score;
void printInfo(){//这是方法的重写
System.out.println("子类printInfo");
}
void printInfo(int score){//这是方法的重载
System.out.println("score:"+score);
}
}
public class Test {
public static void main(String[] args) {
Student stu1 = new Student("李四","男");
stu1.score = 89;
stu1.printInfo();
stu1.printInfo(43);
}
}
六.继承之Object类
1.java中,所有类都是直接或间接继承自java.lang.Object类可以说Object是所有类的祖先即根类
2.java中任何类都继承了Object类中的方法,主要有
toString()
equals()
hashcode()
clone()
getClass()
finalize()
其中比较常用的是toString()和equals()
Object类中的方法toString()
默认的toString()打印的是当前类的虚拟地址
System.out.println(stu1.toString());
输出结果:
com.first.java.Person@659e0bfd
也可以重写该方法让它输出别的字符串
系统的toString是这样的
public String toString() {
// TODO Auto-generated method stub
return super.toString();
}
我们重写试试
public String toString() {
return "重写后:"+name+sex;
}
输出结果:
重写后:你好男人
equals
比较两个对象是否相等
Person stu1 = new Person();
stu1.name = "你好";
stu1.sex = "男人";
Person stu2 = new Person();
stu2.name = "你好";
stu2.sex = "男人";
System.out.println(stu1.equals(stu2));
输出结果:
false
虽然两个对象的属性或属性的方法都是一样的但是Object比较的是虚拟地址
所以会输出false
equals的原型
public boolean equals(Object arg0) {
// TODO Auto-generated method stub
return super.equals(arg0);
}
改写后
public boolean equals(Object arg0) {
Person p = (Person)arg0;
if(this.name == p.name && this.sex == p.sex)
return true;
else
return false;
}
修改后的输出结果:
true
七.继承后可以通过父类新建子类对象
class Person{
String name;
void printInfo(){
System.out.println("name:"+name);
}
Person(String name){
this.name = name;
}
}
class Student extends Person{
Student(String name){
super(name);
}
void printInfo(){
System.out.println("student name:"+name);
}
}
public class Test2 {
public static void main(String[] args) {
Student stu1 = new Student("hello");
Person stu2 = new Student("world");
stu1.printInfo();
stu2.printInfo();
}
}
输出结果
student name:hello
student name:world
另类的实例化方式
......此前省略的在"九.类继承之简单工厂模式.先上代码处"......
class Factory
{
static Fruit getFruit(String name){
if(name == "苹果"){
return new Apple(name);
}else if(name == "梨"){
return new Peach(name);
}else
return null;
}
}
public class Test {
public static void main(String[] args) {
Fruit apple = Factory.getFruit("苹果");
apple.grup();
Factory.getFruit("梨").grup();
}
}
输出结果
Apple:苹果
Peach:梨
九.类继承之简单工厂模式
一.先上代码
class Fruit
{
String name;
void grup(){
System.out.println("水果");
}
Fruit(String name){
this.name = name;
}
}
class Apple extends Fruit{
void grup(){
System.out.println("Apple:"+name);
}
Apple(String name){
super(name);
}
}
class Peach extends Fruit{
void grup(){
System.out.println("Peach:"+name);
}
Peach(String name){
super(name);
}
}
class Factory
{
static Fruit getFruit(String name){
if(name == "苹果"){
return new Apple(name);
}else if(name == "梨"){
return new Peach(name);
}else
return null;
}
}
public class Test {
public static void main(String[] args) {
Factory.getFruit("苹果").grup();
Factory.getFruit("梨").grup();
}
}
输出结果
Apple:苹果
Peach:梨
类比范例:
被对比的是
class Factory
{
static Fruit getFruit(String name){
if(name == "苹果"){
return new Apple(name);
}else if(name == "梨"){
return new Peach(name);
}else
return null;
}
}
用来对比的是
class Abc
{
String name;
void printInfo(){
System.out.println(name);
}
Abc(String name){
this.name = name;
}
static Abc nihao(String name){
return new Abc(name);
}
}
public class Test1 {
public static void main(String[] args) {
Abc.nihao("世界").printInfo();
}
}
因为前面说的static中不能使用this所以重新写一个构造方法,来达到带参数定义new类的目的;
十.抽象方法
一.抽象方法和抽象类
Java中可以定义没有方法体的方法,该方法由子类来具体实现。该没有方法体的方法我们称之为抽象方法,含有抽象方法的类我们称之为抽象类。
二.抽象方法的特点
1.只有方法头没有方法体的方法称为抽象方法
2.抽象方法用abstract来修饰
3.抽象方法代表一种不确定的方法或行为
4.抽象方法不能被调用
三.抽象类的特点
1.定义中含有抽象方法的类叫做抽象类
2.抽象类用abstract来修饰.
3.抽象类代表一种抽象的对象类型
4.抽象类不能实例化
5.抽象类中可以有具体的方法,可以没有抽象方法
//A是一个抽象类
public abstract class A{
public void methodA(){
}
public abstract void methodB();
}
四.怎么使用抽象类
使用方法一
abstract class demo{
abstract void printInfo();
}
public class Test {
public static void main(String[] args) {
demo p = new demo() {
void printInfo() {
// TODO Auto-generated method stub
System.out.println("print demo");
}
};
p.printInfo();
}
}
使用方法二
一般我们继承抽象类来使用
abstract class demo{
abstract void printInfo();
}
class demo2 extends demo{
void printInfo(){
System.out.println("print demo2");
}
}
public class Test {
public static void main(String[] args) {
demo p = new demo2();
p.printInfo();
}
}
十一.接口
一 .接口和继承的区别
接口强调的是有相同的行为行为没有父子类的关系
继承是继承属性和方法,有父子类的关系
二.接口的语法
interface 接口名{
//公有静态常量、抽象方法
}
三.接口的特点
接口中只能存放静态常量和抽象方法
java接口是对功能的拓展
通过实现接口,java类可以实现多实现
一个类可以继承(extends)一个父类并且实现(implement)
多个接口
接口和接口之间可以使用extends实现继承
四.接口和抽象类的区别
1.抽象类和具体实现是一个继承关系,也就是采取抽象类的方式,则父类和子类概念上是相同的 is-a
2.接口和实现类在概念上不要求相同,接口只是抽取相互之间没有关系的共同特征,而不去关注类之间的关系,它可以使没有层次关系的类具有相同行为
3.抽象类是一对具有相同属性和行为的逻辑上有关系的事物的一种抽象,而接口是对一组具有相同属性和行为的逻辑上不相关的事物的一种抽象
代码范例
interface behavior{
abstract void eat();
abstract void drink();
}
class man implements behavior{
public void eat() {
// TODO Auto-generated method stub
System.out.println("男人吃");
}
public void drink() {
// TODO Auto-generated method stub
System.out.println("男人喝");
}
}
class maleDog implements behavior{
public void eat() {
// TODO Auto-generated method stub
System.out.println("公狗吃");
}
public void drink() {
// TODO Auto-generated method stub
System.out.println("公狗喝");
}
}
public class Test {
public static void main(String[] args) {
new man().eat();
new maleDog().eat();
}
}
十二.内部类
一.带名字的内部类
概念:定义在一个类内部的类称为内部类
public class Outer{
class Inner{
//内容
}
}
特点
1.内部类可以很好地实现隐藏,可以使用protected private修饰符
2.内部类可以直接访问外部类的所有成员,包括私有成员
3.外部类不能直接访问内部类的成员,必须首先建立内部类的对象才能访问
成员内部类及应用
1.成员内部类属于外部类的实例成员,成员内部类可以有public 、private 、default 、protected权限修饰符。在成员内部类访问外部类的成员方法和属性,要使用“外部类名.this.成员方法” 和“外部类名.this.成员属性”的形式
2.创建成员内部类的实例使用"外部类名.内部类名 实例 = 外部类实例例名.new 内部类构造方法(参数)"的形式
成员内部类有一下限制
1.成员内部类不能与外部类重名
2.不能在成员内部类定义static属性,方法和类(static final形式的常量定义除外),因为一个成员内部类必然和一个外部类实例关联,static成员完全可以移到其外部类中去
代码
class Outer
{
int data;
void printInfo(){
System.out.println("外部类");
}
//外部类不能直接访问内部类的成员,必须首先建立内部类的对象才能访问
void visitInner(){
Inner I = new Inner();
System.out.println("外部类调用内部类data="+I.data);
}
class Inner{//内部类不能与外部类重名
int data;
void Innerprint(){
System.out.println("内部类");
//内部类调用外部类的属性和方法
//外部类名.this.成员方法
Outer.this.printInfo();
//外部类名.this.成员属性
System.out.println("外部类data="+Outer.this.data);
}
}
}
public class Test {
public static void main(String[] args) {
//外部类名.内部类名 实例 = 外部类实例例名.new 内部类构造方法(参数)
Outer a;
a = new Outer();//先实例化一个对象
a.visitInner();
Outer.Inner p = a.new Inner();//通过外部类的对象new一个内部类
p.Innerprint();
}
}
二.匿名内部类
是说在mian函数里面引用的时候
new demo(){
System.out.println("这是匿名内部类");
};
这里实例化对象时不像
demo demo1 = new demo();
有个demo1的名称.
匿名内类的特点
1.匿名内部类是没有名称的内部类,没有办法引用他们,必须在创建时,作为new语句的一部分来声明并创建他们的实例
2.匿名内部类必须继承一个类(抽象的,非抽象的都可以)或者实现一个接口,所有父类(或者父接口)是抽象类,则匿名内部类必须实现七所有抽象方法
//语法实例:
new interface/superclass(){类体}
这种形式的new语句声明一个新的匿名类,它对一个给定的类进行扩展,或者实现一个给定的接口,并同时创建该匿名类的一个新实例.
代码
abstract class Demo1{
abstract void printInfo();
}
interface Demo2{
abstract void interprint();
}
public class Test {
public static void main(String[] args) {
new Demo1() {
void printInfo() {
// TODO Auto-generated method stub
System.out.println("这不是demo1,而是匿名内部类的方法.");
}
}.printInfo();
new Demo2() {
public void interprint() {
// TODO Auto-generated method stub
System.out.println("这不是接口,是匿名内部类的方法");
}
}.interprint();
}
}
十三. 多态
一.多态的概念
多态是指同一个操作作用于 某一类对象,可以有不同的解释,产生不同的执行结果
多态存在的三个必要条件:
1.需要存在的继承和实现方法
2.同样的方法调用而执行不同的操作,运行不同代码(重写)
3.在运行父类或接口的引用变量可以引用其子类的对象多态的作用.
多态的作用
1.多态通过分离做什么和怎么做,从一个角度将接口和实现进行分离
2.多态消除了类型之间的耦合关系
3.多态的存在提高了程序的拓展性和可维护性.
二.对象的上下转型
代码
import java.net.InterfaceAddress;
class Animal
{
String name;
void eat(){};
}
class Dog extends Animal
{
void eat() {
// TODO Auto-generated method stub
System.out.println("Dog eat shit");
}
}
class Cat extends Animal
{
void eat() {
// TODO Auto-generated method stub
System.out.println("Cat eat fish");
}
}
public class Test {
public static void main(String[] args) {
Animal dog = new Dog();//这就是向上转型
//没有转型的例子怎样的呢?
//Dog dog = new Dog();
Animal cat = new Cat();//这就是向上转型
Animal an1 = new Cat();
dog.eat();
cat.eat();
if(an1 instanceof Cat){
System.out.println("没有报错的向下转型");
Cat an2 = (Cat)an1;//这是向下转型
an2.eat();
}
//Dog an3 = (Dog)an1;//这也是向下转型,但是会报错,因为an1不是Dog的子类
}
}
1.由子类成父类,在继承图上是向上移动的,一般称为向上转型
2.向上转型是从一个较专用类型向通用类型的转换,所以总是安全的,也就是说子类是父类的超集
3.向上转型过程中,类接口中唯一可能发生的事情是丢失方法,而不是获取方法
4.与之相反的操作是向下转型,不安全(可能需要instanceof操作符协助)
an2.eat();也要写进if语句里面
三.多态的应用实例
class School
{
Dayin dayin;
void anZhuang(Dayin dayin){
this.dayin = dayin;
}
void print(String context){
dayin.print(context);
}
}
class Dayin
{
void print(String context){};
}
class CaiseDayin extends Dayin
{
void print(String context) {
// TODO Auto-generated method stub
System.out.println("彩色打印"+context);
}
}
class HeibaiDayin extends Dayin
{
void print(String context) {
// TODO Auto-generated method stub
System.out.println("黑白打印 "+context);
}
}
public class Test {
public static void main(String[] args) {
School sch1 = new School();
School sch2 = new School();
Dayin d1 = new CaiseDayin();
Dayin d2 = new HeibaiDayin();
sch1.anZhuang(d1);
sch1.print("你好 世界");
sch2.anZhuang(d2);
sch2.print("hello world");
}
}
输出结果
彩色打印你好 世界
黑白打印 hello world
十四.异常概念及分类
一.error
涉及到java虚拟机
二.exception
1.io exception
2.runtime exception
三.受查异常
编译就通不过的异常
四.非受查异常
编译可以通过,但是运行的时候会崩.
三.异常的处理机制
1.try
监控执行时可能产生的异常
2.catch
捕获异常
3.finally
善后处理不管是否发生异常代码始终可以运行
代码
class Person{
void print(){
System.out.println("hello world");
}
}
public class Test {
public static void main(String[] args) {
Person p = null;
try{
p.print();
}finally{
System.out.println("end");
}
}
}
输出结果
end
Exception in thread "main" java.lang.NullPointerException
at Test.main(Test.java:10)
class Person{
void print(){
System.out.println("hello world");
}
}
public class Test {
public static void main(String[] args) {
Person p = null;
try{
p.print();
}catch(java.lang.NullPointerException e){
//也可以用 Exception e 代替括号内的参数,Exception不抓所有异常
System.out.println("空指针检查下有没有初始化类");
}finally{
System.out.println("end");
}
}
}
四.throw和throws
throw:主动抛出异常
throws:声明可能会出现的异常
class Bar
{
int age;
public Bar(int age)
{
this.age = age;
}
void check()throws IllegalArgumentException{
if (age < 18){
throw new IllegalArgumentException("年纪太小");
}
}
}
public class Test {
public static void main(String[] args) {
Bar b = new Bar(15);
try{
b.check();
}catch (IllegalArgumentException e){
System.out.println(e.getMessage());
e.printStackTrace();
}
System.out.println("end");
}
}
输出结果
年纪太小
end
java.lang.IllegalArgumentException: 年纪太小
at Bar.check(Test.java:10)
at Test.main(Test.java:18)
十五.泛型
一.泛型简介
在JDK1.5之后引入
1.泛型可以在编译的时候检查类型安全,并且所有的强制转换都是自动和隐藏的
2.泛型的原理就是"类型的参数化",即把类型看做参数.也就是说,把所要操作的数据类型看做参数,就像方法的形式参数是运行时传递的值的占位符一样.
3.简单的说,类型变量扮演的角色就如同一个参数,他提供编译器用来类型检查的信息
4.泛型可以提高代码的扩展性和重用性.
方法相同,对象不同的类
针对这种情况,避免创建过多的类,创建数据类型的时候,可以使用Object
代码示例
class Cls{
Object a;
public Cls (Object a) {
this.a = a;
}
public Object getData() {
return a;
}
}
public class Test2 {
public static void main(String[] args) {
Cls cls = new Cls(10);
Cls cls1 = new Cls("10");
System.out.println(cls.getData());
System.out.println(cls1.getData());
}
}
Object,强转的时候不会提示错误,但是运行的时候会出现错误
比如把最后一句改成如下所示
System.out.println((Integer)cls1.getData());
输出结果
10
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at Test2.main(Test2.java:15)
代码示例
class Cls1<T>
{
T a;
public Cls1(T a){
this.a = a;
}
public T getData(){
return a;
}
}
public class Test {
public static void main(String[] args) {
Cls1<Integer> cls1 = new Cls1<Integer>(10);
Cls1<String> cls2 = new Cls1<String>("10");
System.out.println(cls1.getData());
System.out.println(cls2.getData());
}
}
二.泛型类及其特点
1.泛型类型的参数可以是泛型类
Cls1<Cls1<Integer>> cls5 = new Cls1<Cls1<Integer>>(new Cls1<Integer>(10));
System.out.println(cls5.getData().getData());//第一个getData出来的还是泛型,所以还要加一个getData
2.泛型类可以同时设置多个类型参数
class Cls<T,T2>{};
调用
Cls2<Integer,String> cls3 = new Cls2<Integer,String>(10,"10");
3.泛型类可以继承泛型类
class Cls1<T>
{
T a;
public Cls1(T a){
this.a = a;
}
public T getData(){
return a;
}
}
class Cls2<T,T2> extends Cls1<T>
{
T2 b;
public Cls2(T a,T2 b){
super(a);
this.b = b;
}
public T getData(){
return a;
}
public T2 getData2() {
return b;
}
}
......略......
泛型还可以写成抽象类的形式
4.泛型类可以实现泛型接口
abstract class Cls1<T>
{
T a;
public Cls1(T a){
this.a = a;
}
public T getData(){
return a;
}
abstract void infoPrint();
}
interface Cls3<T3>{
abstract void printInfoInCls3(T3 t);
}
class Cls2<T,T2,T3> extends Cls1<T> implements Cls3<T3>
{
T2 b;
public Cls2(T a,T2 b){
super(a);
this.b = b;
}
public T getData(){
return a;
}
public T2 getData2() {
return b;
}
@Override
void infoPrint() {
// TODO Auto-generated method stub
System.out.println(b);
}
@Override
public void printInfoInCls3(T3 t) {
// TODO Auto-generated method stub
System.out.println(t);
}
}
public class Test2 {
public static void main(String[] args) {
Cls2<Integer,String,String> cls = new Cls2<Integer,String,String>(10,"10");
cls.printInfoInCls3("hello");
}
}
三.限制泛型的可用类型
1.在定义泛型的类别时,默认在实例化泛型的时候可以使用任何类型,但是如果想要限制使用泛型类型时,只能用某个特定类型或者其子类型才能实例化该类型时,可以在定义类型时,使用extends关键字指定这个类型必须是继承某个类,或者实现某个接口.
2.当没有指定泛型继承的类型或接口时,默认使用extends Object,所以默认情况下任何类型都可以作为参数传入.
class Aniaml{
}
class Dog extends Aniaml{
}
abstract class Cls1<T extends Aniaml>
{
T a;
public Cls1(T a){
this.a = a;
}
public T getData(){
return a;
}
abstract void infoPrint();
}
interface Cls3<T3>{
abstract void printInfoInCls3(T3 t);
}
class Cls2<T extends Aniaml,T2,T3> extends Cls1<T> implements Cls3<T3>
{
T2 b;
public Cls2(T a,T2 b){
super(a);
this.b = b;
}
public T getData(){
return a;
}
public T2 getData2() {
return b;
}
@Override
void infoPrint() {
// TODO Auto-generated method stub
System.out.println(b);
}
@Override
public void printInfoInCls3(T3 t) {
// TODO Auto-generated method stub
System.out.println(t);
}
}
public class Test2 {
public static void main(String[] args) {
Cls2<Aniaml,String,String> cls = new Cls2<Aniaml,String,String>(new Dog(),"10");
cls.printInfoInCls3("hello");
}
}
四.泛型的通配声明
1.同一泛型类,如果实例化时给定的实际类型不同,则这些实例的类型是不兼容的,不能互相赋值.
class Cls5<T>
{
T a;
public Cls5(T a){
this.a = a;
}
public T getData(){
return a;
}
void infoPrint(){
}
}
public class Test {
public static void main(String[] args) {
Cls5<Integer> a = new Cls5<Integer>(10);
Cls5<Double> b = new Cls5<Double>(10.1);
a = b;//编译的时候会报错
}
}
2.泛型通配方式
1)"?"代表任意一个类型
Cls5<?> c;
c = b;
2)和限制泛型的上限相似,同样可以通过使用extends关键字限定通配类型上限:
public static void main(String[] args) {
Cls5<Integer> a = new Cls5<Integer>(10);
Cls5<Double> b = new Cls5<Double>(10.1);
Cls5<?> c;
c = b;
Cls5<? extends String> d;
d = a;//会报错
//a = b;//编译的时候会报错
}
3)还可以使用super关键
class Aniaml{
}
class Dog extends Aniaml{
}
abstract class Cls1<T extends Aniaml>
{
T a;
public Cls1(T a){
this.a = a;
}
public T getData(){
return a;
}
abstract void infoPrint();
}
...略...
Cls1<Dog> b = new Cls1<Dog>(null) {
@Override
void infoPrint() {
// TODO Auto-generated method stub
}
};
Cls1<? super Dog> a = b;//这里尖括号里的问号表示?是Dog的父类
五.泛型方法
1.不仅类可以声明泛型,类中的方法也可以声明仅用于自身的泛型,这种方法称为泛型方法,其定义格式为:
访问修饰符<泛型列表>返回类型 方法名(参数列表){
实现代码
}
泛型方法比方法的重载好用
class A{
void print(char t){
System.out.println(t);
}
//方法的重载
void print(int a){
System.out.println(a);
}
}
class B{
public <T> void printInfo(T t){
System.out.println(t);
}
//泛型方法的重载
public <T,T2> void printInfo (T t,T2 t2) {
System.out.println(t);
System.out.println(t2);
}
}
public class Test {
public static void main(String[] args) {
B b = new B();
b.printInfo("helo");
b.printInfo(12);
b.printInfo(1.2);
b.printInfo('a');
A a = new A();
a.print('d');
a.print(1);
b.printInfo(1, 1);
}
}
2.在泛型列表中声明的泛型,可以用于该方法的返回类型,参数类型声明和方法代码中的局部变量的类型声明.
public <T,T2> T printInfo (T t,T2 t2) {
System.out.println(t);
System.out.println(t2);
return t;
}
3.类中其他方法不能使用当前方法声明的泛型
提示:是否拥有泛型方法,与其所在的类是否泛型没有关系.要定义泛型方法,只需要将泛型参数列表置于返回值前.
4.什么时候使用泛型方法?
1)添加类型约束作用于一个方法的多个参数之间,而不涉及到类中的其他方法.
2)施加类型约束的方法称为静态方法,只能将其定义为泛型方法,因为静态方法不能使用其所在类的类型参数.
class Animal{
void print(){
System.out.println("Animal eat");
}
}
class Dog extends Animal{
void print(){
System.out.println("Dog eat");
}
}
class A{
public static <T extends Animal> void print(T t){
t.print();
}
}
public class Test {
public static void main(String[] args) {
A a = new A();
a.print(new Dog());
A.print(new Dog());//静态方法可以直接这样使用,不用实例化一个对象例如"a"
}
}
十六.final关键字
final关键字
成员员变量之实例变量
实例变量有默认值,并且final变量一旦赋值之后就不可再重新赋值,所以java语言最终规定实例变量使用final修饰后,必须手动赋值,不能采取系统默认值。
- final是一个关键字,表示的是最终的,不可变的。
- final修饰的类无法继承
- final方法无法被覆盖
- final修饰的变量一旦赋值不可再重新赋值
- final修饰的实例变量必须手动赋值,不可采用系统默认值
- final修饰的引用,一旦指向某个对象之后,不能再指向其他的对象,那么被指向的对象无法被垃圾回收站回收
- final修饰的引用虽然指向某个对象之后不可以在指向其他的对象,但是所指向的对象内部的内存可以被修改的
十七.java类型的强制转换
字符串转成整型
int i = Integer.parseInt(String str);
int i = Integer.valueOf().intValue();
整型转成字符串
String str = String.valueOf(int i);
String str = Integer.toString(int i);
String str = “” + i ;