Go语言基础之18--接口编程
一、接口介绍和定义
1.1 接口定义了一个对象的行为规范
A. 只定义规范,不实现
B. 具体的对象需要实现规范的细节
葵花宝典:
接口就是一层封装,1个例子,封装一个返还浏览器内容的接口。为什么不直接面向对象呢。你封装成一个接口的话,不论是返回文件或者图片或者html都可以通过接口进行返回,不用接口的话,你需要为每一种返回类型写函数。
1.2 Go中接口定义
A. type 接口名字 interface
B. 接口里面是一组方法签名的集合(后面的调用参数和返回值都要和接口中的方法一模一样)
C.接口是引用类型(指针);注意:函数传递接口类型参数时,一定不要加*,因为接口本身就是引用类型,如果加*就报错了
type Animal interface {
Talk()
Eat() int
Run()
}
1.3 Go中接口的实现
A. 在Go语言中,一个类只要实现了接口要求的所有函数,我们就说这个类实现了该接口
B. 接口类型的变量可以保存实现该接口的任何具体类型的实例。
实例:
package main import (
"fmt"
) type Animal interface { //定义了动物的规范(接口定义的一组方法)
Eat()
Talk()
Run()
} type Dog struct { //狗如果能够满足了动物的规范(接口方法),那其就是动物
name string
} func (d *Dog) Eat() { //目前狗还不是动物,因为其只实现了Eat,还需要实现Talk和Run,其才算是动物
fmt.Printf("%s is eating\n", d.name)
} func (d *Dog) Talk() {
fmt.Printf("%s is talking\n", d.name)
} func (d *Dog) Run() {
fmt.Printf("%s is runing\n", d.name)
} func (d *Pig) Eat() {
fmt.Printf("%s is eating\n", d.name)
} func (d *Pig) Talk() {
fmt.Printf("%s is talking\n", d.name)
} func (d *Pig) Run() {
fmt.Printf("%s is runing\n", d.name)
} func main() {
var dog = &Dog{
name: "旺财",
} var a Animal
fmt.Printf("a:%v dog:%v\n", a, dog) //接口底层就是指针,指向的就是一个空对象,如果字节调用就会panic a = dog //dog满足了接口所有方法,所以我们可以直接将其复制给Animal,对应的理论就是接口类型的变量可以保存实现该接口的任何具体类型的实例。
a.Eat()
a.Run()
a.Talk() var pig = &Pig {
name:"佩奇",
} a = pig
a.Eat()
a.Run()
a.Talk()
}
执行结果:
上面这个例子中,Pig和Dog实现了Animal的所有方法,所以Cat和Dog都是动物
小结一下:
Go中的接口只要一个对象实现了接口类型中的所有方法,那么这个对象就实现了这个接口,当然如果一个对象实现了多个interface类型的方法,那么这个对象就实现了多个接口
1.4 接口实例
A. 一个公司需要计算所有职员的薪水
B. 每个职员的薪水计算方式不同
如何解答呢?
我们先单纯通过结构体进行解答:
结构体示例:
package main import (
"fmt"
) type Developer struct { //开发
Name string
Base int
} func (d *Developer) Calc() int {
return d.Base
} type PM struct { //pm
Name string
Base int
Option int
} func (p *PM) Calc() int {
return p.Base + p.Option
} type YY struct { //运营
Name string
Base float32
Option float32
Rate float32 //0.6 ~ 3
} func (p *YY) Calc() float32 {
return p.Base + p.Option*p.Rate
} type EmployeeMgr struct { //最终汇总
devList []*Developer //用切片存
pmList []*PM
yyList []*YY
} func (e *EmployeeMgr) Calc() float32 { //进行计算
var sum float32
for _, v := range e.devList { //计算程序员
sum += float32(v.Calc())
} for _, v := range e.pmList { //计算pm
sum += float32(v.Calc())
} for _, v := range e.yyList { //计算运营
sum += float32(v.Calc())
} return sum
} func (e *EmployeeMgr) AddDev(d *Developer) { //人从哪来,要添加人,添加到列表的函数
e.devList = append(e.devList, d)
} func (e *EmployeeMgr) AddPM(d *PM) {
e.pmList = append(e.pmList, d)
} func (e *EmployeeMgr) AddYY(d *YY) {
e.yyList = append(e.yyList, d)
} func main() {
var e = &EmployeeMgr{} dev := &Developer{ //添加具体人
Name: "develop",
Base: ,
}
e.AddDev(dev) pm := &PM{
Name: "pm",
Base: ,
Option: ,
}
e.AddPM(pm) yy := &YY{
Name: "yy",
Base: ,
Option: ,
Rate: 1.2,
}
e.AddYY(yy) sum := e.Calc() //计算所有人
fmt.Printf("sum:%f\n", sum)
}
执行结果:
解释:
单纯用结构体实现有一个很大的弊端就是如果我们要添加一个职位的话,非常不方便,要改动地方太多,比如:增加职位结构体(类)、结构体方法、计算方式添加、增加进总列表,十分的不灵活,下面我们来看看通过接口实现怎么样
接口实例:
package main import (
"fmt"
) type Employee interface { //定义1个雇员的接口,其规定的方法是calc(计算工资)
Calc() float32 //接下来的各种职位要想使用这个接口,就需要有该接口规定的方法,并且类型也要一致
} type Developer struct {
Name string
Base float32
} func (d *Developer) Calc() float32 {
return d.Base
} type PM struct {
Name string
Base float32
Option float32
} func (p *PM) Calc() float32 {
return p.Base + p.Option
} type YY struct {
Name string
Base float32
Option float32
Rate float32 //0.6 ~ 3
} func (p *YY) Calc() float32 {
return p.Base + p.Option*p.Rate
} type EmployeeMgr struct {
employeeList []Employee //员工管理列表不需要在区分职位了,只需要1个职员列表即可(因为无论是dev还是pm、yy都实现了employee的接口)
} func (e *EmployeeMgr) Calc() float32 { //计算也是都统一一个了
var sum float32
for _, v := range e.employeeList {
sum += v.Calc()
} return sum
} func (e *EmployeeMgr) AddEmpoyee(d Employee) { //追加也是都只有1个了,并且这里参数也不需要加*,因为interface自身就是引用类型。
e.employeeList = append(e.employeeList, d)
} func main() {
var e = &EmployeeMgr{} dev := &Developer{
Name: "develop",
Base: ,
}
e.AddEmpoyee(dev) pm := &PM{
Name: "pm",
Base: ,
Option: ,
}
e.AddEmpoyee(pm) yy := &YY{
Name: "yy",
Base: ,
Option: ,
Rate: 1.2,
}
e.AddEmpoyee(yy) sum := e.Calc()
fmt.Printf("sum:%f\n", sum)
}
执行结果:
解释:
可以发现用接口来实现,非常方便,新增加一个职位,只需要增加一个职位的类和方法以及该职位职员相关信息即可,十分方便了。
1.5 接口类型变量
A. var a Animal
B. 那么a能够存储所有实现Animal接口的对象实例
实例参考Dog和Pig的实例。
二、空接口
2.1 空接口
A. 空接口没有定义任何方法
B. 所以任何类型都实现了空接口,所以空接口就可以用来存储任何类型的实例。
有一个思考,空接口这么牛逼,可以存储任何类型,那我岂不是可以随意用空接口了?
答:这样不好,首先go语言本身是一个强类型语言,规定传什么类型参数就传什么类型,强类型语言通过规定了,能够提高性能,这也是其的一大特点,而如果不规定,用途就模糊不清了,那样维护性差,可操作性低,就丧失了go的优势了。
interface { }
实例如下:
package main import (
"fmt"
) func main() {
var a interface{} //定义1个空接口
var b int a = b //a是空接口,所以可以存储任何类型
fmt.Printf("a=%v a:%T\n", a, a)
var c float32 a = c
fmt.Printf("a=%v a:%T\n", a, a)
}
执行结果:
实例2:
package main import (
"fmt"
) func describe(i interface{}) {
fmt.Printf("Type = %T, value = %v\n", i, i)
} func main() {
s := "hello world"
describe(s) //空接口可以存string
i :=
describe(i) //空接口可以存int
strt := struct {
name string
}{
name: "Naveen R",
}
describe(strt) //空接口可以存struct,可以证明其可以存储任意类型
}
执行结果:
三、类型断言
3.1 如何获取接口类型里面存储的具体的值呢?
实例1:
package main import (
"fmt"
) type Animal interface {
Eat()
} type Dog struct {
name string
} func (d *Dog) Eat() {
fmt.Printf("%s is eating\n", d.name)
} type Pig struct {
name string
} func (d *Pig) Eat() {
fmt.Printf("%s is eating\n", d.name)
} //类型断言
func Describe(a Animal) { //注意Animal(接口)本身就是引用类型,这里不能加*,加上会报错
dog := a.(*Dog) //将animal指定为dog(但是animal中不一定只有dog)
dog.Eat()
} func main() {
var dog = &Dog{
name: "旺财",
} var a Animal
a = dog
fmt.Printf("I am dog\n")
Describe(a) //dog调用类型断言的describe函数 var pig = &Pig{
name: "佩奇",
} a = pig
fmt.Printf("I am pig\n")
Describe(a) //pig也调用类型断言的describe函数
}
执行结果:
解释:
可以发现直接报错了,这是因为我们强行将animal定为dog,但是animal中还有pig,所以pig在调用describe函数时,就冲突了,就报错了。这是一个很大的坑,如何解决呢?
解决办法:
引入 ok判断机制!
实例如下:
package main import (
"fmt"
) type Animal interface {
Eat()
} type Dog struct {
name string
} func (d *Dog) Eat() {
fmt.Printf("%s is eating\n", d.name)
} type Pig struct {
name string
} func (d *Pig) Eat() {
fmt.Printf("%s is eating\n", d.name)
} //类型断言
func Describe(a Animal) { //注意Animal(接口)本身就是引用类型,这里不能加*,加上会报错
dog, ok := a.(*Dog) //引入ok判断机制
if !ok {
fmt.Printf("convert to dog failed\n")
return
}
fmt.Printf("describe suncc\n")
dog.Eat()
fmt.Printf("describe suncc----------\n")
} func main() {
var dog = &Dog{
name: "旺财",
} var a Animal
a = dog
fmt.Printf("I am dog\n")
Describe(a) var pig = &Pig{
name: "佩奇",
} a = pig
fmt.Printf("I am pig\n")
Describe(a)
}
执行结果:
解释:
我们可以发现引入ok判断机制后,将animal定为dog,但是animal中还有pig,当确定dog时就会执行成功,而是pig则就会失败。
实例2:
package main import (
"fmt"
) func assert(i interface{}) {
s := i.(int) //将空接口传入的类型定为int
fmt.Println(s)
} func main() {
var s interface{} = "harden"
assert(s)
}
执行结果:
解决上述报错:
引入ok机制:
package main import (
"fmt"
) func assert(i interface{}) {
v, ok := i.(int) //将空接口传入的类型定为int
fmt.Println(v, ok)
} func main() {
var s interface{} =
assert(s)
var i interface{} = "harden"
assert(i)
}
执行结果:
3.2 type switch
方法1:问题:需要转2次
实例1:
package main import (
"fmt"
) type Animal interface {
Eat()
} type Dog struct {
name string
} func (d *Dog) Eat() {
fmt.Printf("%s is eating\n", d.name)
} type Pig struct {
name string
} func (d *Pig) Eat() {
fmt.Printf("%s is eating\n", d.name)
} //types switch
func DescribeSwitch(a Animal) {
fmt.Printf("DescribeSwitch(a) begin\n")
switch a.(type) { //格式是固定的,type是一个关键字 //强制转第一次type关键字
case *Dog: //强制转换成dog(强制转第二次)
dog := a.(*Dog)
dog.Eat()
case *Pig: //强制转成pig(强制转第二次)
pig := a.(*Pig)
pig.Eat()
}
fmt.Printf("DescribeSwitch(a) end\n")
} func main() {
var dog = &Dog{
name: "旺财",
} var a Animal
a = dog
fmt.Printf("I am dog\n")
DescribeSwitch(a) var pig = &Pig{
name: "佩奇",
} a = pig
fmt.Printf("I am pig\n")
DescribeSwitch(a)
}
执行结果:
实例2:
package main import (
"fmt"
) func findType(i interface{}) {
switch i.(type) {
case string:
fmt.Printf("I am a string and my value is %s\n", i.(string))
case int:
fmt.Printf("I am a int and my value is %d\n", i.(int))
default:
fmt.Printf("Unknown type\n")
}
} func main() {
findType("hello")
findType()
findType(88.98)
}
执行结果:
方法2:(推荐) 解决需要转2次问题
实例1:
package main import (
"fmt"
) type Animal interface {
Eat()
} type Dog struct {
name string
} func (d *Dog) Eat() {
fmt.Printf("%s is eating\n", d.name)
} type Pig struct {
name string
} func (d *Pig) Eat() {
fmt.Printf("%s is eating\n", d.name)
} //types switch
func DescribeSwitch(a Animal) {
fmt.Printf("DescribeSwitch(a) begin\n")
switch v := a.(type) { //格式是固定的,type是一个关键字
case *Dog:
v.Eat() //v就是断言之后的具体类型
case *Pig:
v.Eat()
}
fmt.Printf("DescribeSwitch(a) end\n")
} func main() {
var dog = &Dog{
name: "旺财",
} var a Animal
a = dog
fmt.Printf("I am dog\n")
DescribeSwitch(a) var pig = &Pig{
name: "佩奇",
} a = pig
fmt.Printf("I am pig\n")
DescribeSwitch(a)
}
执行结果:
实例2:
package main import (
"fmt"
) func findType(i interface{}) {
switch v := i.(type) {
case string:
fmt.Printf("I am a string and my value is %s\n", v)
case int:
fmt.Printf("I am a int and my value is %d\n", v)
default:
fmt.Printf("Unknown type\n")
}
} func main() {
findType("hello")
findType()
findType(88.98)
}
执行结果:
四、指针接收和值接收
葵花宝典:
指针类型实现的接口,值类型是赋值不了的。但是值类型实现的接口,指针类型依然可以赋值
例子如下:
比如说Dog是通过指针类型实现的接口:
当我们进行值类型赋值就会报错:
我们可以通过传入地址来解决:
但如果Dog是值类型实现的接口:
我们的指针类型对其进行赋值依然没问题:
这是因为go在传入时帮我们将指针类型转换为了值类型。
五、多接口
5.1 多接口
同一个类型可以实现多个接口。
比如说狗是一个动物,它可以实现动物的接口,狗同时还是一个哺乳动物,他也可以实现哺乳动物的接口。重要的是:只要把多个接口的方法都实现了,那么其就可以实现多个接口。
package main import (
"fmt"
) //定义2个接口
type Animal interface {
Eat()
} type BuRuAnimal interface {
ChiNai()
} type Dog struct {
name string
} //Dog实现了上述2个接口的方法,所以其也实现了上述2个接口
func (d *Dog) Eat() {
fmt.Printf("%s is eating\n", d.name)
} func (d *Dog) ChiNai() {
fmt.Printf("%s is ChiNai\n", d.name)
} func main() {
var dog = &Dog{
name: "旺财",
} var a Animal
fmt.Printf("a:%v dog:%v\n", a, dog)
a = dog
a.Eat() var b BuRuAnimal
b = dog
b.ChiNai()
}
执行结果:
5.2 接口嵌套
package main import (
"fmt"
) //定义2个接口
type Animal interface {
Eat()
} type BuRuAnimal interface {
ChiNai()
} //接口嵌套
type AdvanceAnimal interface { //要想实现AdvanceAnimal接口,那么就需要满足嵌套的接口的所有方法
Animal
BuRuAnimal
} type Dog struct {
name string
} func (d *Dog) Eat() {
fmt.Printf("%s is eating\n", d.name)
} func (d *Dog) ChiNai() {
fmt.Printf("%s is ChiNai\n", d.name)
} func main() {
var dog = &Dog{
name: "旺财",
} var a AdvanceAnimal
fmt.Printf("a:%v dog:%v\n", a, dog)
a = dog
a.Eat()
a.ChiNai()
}
执行结果:
六、接口实例讲解
6.1 io包中的writer接口
底层writer接口的规定的方法:
实例:
package main import (
"fmt"
"os"
) type Test struct {
data string
} //这里实现1个wirter接口的方法
func (t *Test) Write(p []byte) (n int, err error) {
t.data = string(p)
return len(p), nil
} func main() {
file, _ := os.Create("c:/tmp/c.txt")
fmt.Fprintf(os.Stdout, "hello world\n") //输出到终端 (这里FPrintf函数要传入一个writer类型接口,把具体实例os.Stdout传给writer接口)
fmt.Fprintf(file, "hello world\n")
/* 因为writer接口的存在,我们可以省去下面的步骤:
fmt.FPtrintfConsole()
fmt.FPtrintfFile()
fmt.FPtrintfNet()
*/
var t *Test = &Test{}
fmt.Fprintf(t, "this is a test inteface:%s", "?akdfkdfjdkfk\n") //存入到data中了 fmt.Printf("t.data:%s\n", t.data)
}
执行结果:
6.2 fmt包中的Stringer接口
底层stringer接口
实例:
package main import (
"encoding/json"
"fmt"
) type Student struct {
Name string
Age int
} func (s *Student) String() string {
data, _ := json.Marshal(s)
return string(data)
} func main() {
var a = &Student{
Name: "hell",
Age: ,
}
fmt.Printf("a = %v\n", a) //fmt包调Print相关函数时,看传进去的变量是否实现了stringer接口
}
执行结果:
解释:
Printf函数会判断传入的变量a是否实现了stringer接口,stringer接口会调其中的string方法去格式化输出字符串
6.3 error包中的error接口
底层error接口:
type error interface {
Error() string
}
实例1:
package main import (
"fmt"
"time"
) type MyError struct {
When time.Time
What string
} func (e MyError) Error() string {
str := fmt.Sprintf("at %v, %s", e.When, e.What)
fmt.Printf("1:%T\n", str)
return str
}
func run() error {
fmt.Println("")
str := MyError{time.Now(), "it didn't work"}
fmt.Printf("2:%T\n", str)
fmt.Println(MyError{time.Now(), "it didn't work"})
return str
}
func main() {
if err := run(); err != nil {
fmt.Printf("3:%T\n", err)
fmt.Println(err)
}
}
执行结果:
解释:
因为error接口只有1个Error方法,所以我们就可以实现自己的错误类型,此处我们就是定义了myerror结构体,但是我们实现了error方法,在函数中返回时返回error,就把我们自己的错误类型反回给了error接口了
实例2:
package main import (
"fmt"
) type ErrNegativeSqrt float64 func (e ErrNegativeSqrt) Error() string { return fmt.Sprintf("cannot Sqrt negative number:%v", float64(e))
} func Sqrt(x float64) (float64, error) {
if x < {
return , ErrNegativeSqrt(x) //如果小于0,则返回我们自定义的错误
} return x, nil
} func main() {
fmt.Println(Sqrt())
_, err := Sqrt(-)
if err != nil {
switch err.(type) { //类型断言,获取错误码
case ErrNegativeSqrt:
fmt.Printf("ErrNegativeSqrt\n")
default: }
}
}
执行结果:
6.4 Reader接口
实例:
package main import (
"fmt"
_ "strings"
"time"
) type MyReader struct{} // TODO: Add a Read([]byte) (int, error) method to MyReader.
func (r MyReader) Read(b []byte) (int, error) {
b[] = 'A'
return , nil
}
func main() {
var myre MyReader
b := make([]byte, )
//for {
//r := strings.NewReader(b)
myre.Read(b)
fmt.Printf("%c\n", b[])
time.Sleep( * time.Second)
myre.Read(b)
fmt.Println(b[])
//}
}
执行结果:
解释:
定义1个Myreader结构体,下面实现reader方法,实例实现了reader方法,按照定义的read方法去操作。
6.5 Image接口
image接口底层:
type Image interface {
ColorModel() color.Model
Bounds() Rectangle
At(x, y int) color.Color
}
实例:
package main import (
"image"
"image/color" "golang.org/x/tour/pic"
//"fmt"
) type Image struct {
weight int
height int
} func (c Image) ColorModel() color.Model {
return color.RGBAModel
}
func (b *Image) Bounds() image.Rectangle {
return image.Rect(, , b.weight, b.height)
}
func (a *Image) At(x, y int) color.Color {
//fmt.Println(x, y)
return color.RGBA{uint8(x), uint8(y), , }
}
func main() {
m := &Image{, }
//m.At(225, 0)
pic.ShowImage(m) //m.At(x, y)的参数由pic传入,传入了所有情况
}
解释:
定义了image的结构体,下面实现了底层image接口的方法,所以我们就可以传入实例进行操作。
Go语言基础之18--接口编程的更多相关文章
- Python语言基础07-面向对象编程基础
本文收录在Python从入门到精通系列文章系列 1. 了解面对对象编程 活在当下的程序员应该都听过"面向对象编程"一词,也经常有人问能不能用一句话解释下什么是"面向对象编 ...
- PL/SQL语言基础
PL/SQL语言基础 进行PL/SQL编程前,要打开输出set serveroutput on 1.创建一个匿名PL/SQL块,将下列字符输出到屏幕:"My PL/SQL Block Wor ...
- Go语言基础之接口(面向对象编程下)
1 接口 1.1 接口介绍 接口(interface)是Go语言中核心部分,Go语言提供面向接口编程,那么接口是什么? 现实生活中,有许多接口的例子,比如说电子设备上的充电接口,这个充电接口能干什么, ...
- Go语言面组合式向对象编程基础总结
转自:http://blog.csdn.net/yue7603835/article/details/44282823 Go语言的面向对象编程简单而干净,通过非侵入式接口模型,否定了C/C++ Jav ...
- GO学习-(19) Go语言基础之网络编程
Go语言基础之网络编程 现在我们几乎每天都在使用互联网,我们前面已经学习了如何编写Go语言程序,但是如何才能让我们的程序通过网络互相通信呢?本章我们就一起来学习下Go语言中的网络编程. 关于网络编程其 ...
- GO学习-(14) Go语言基础之接口
Go语言基础之接口 接口(interface)定义了一个对象的行为规范,只定义规范不实现,由具体的对象来实现规范的细节. 接口 接口类型 在Go语言中接口(interface)是一种类型,一种抽象的类 ...
- Go语言基础之接口
Go语言基础之接口 接口(interface)定义了一个对象的行为规范,只定义规范不实现,由具体的对象来实现规范的细节. 接口 接口介绍 在Go语言中接口(interface)是一种类型,一种抽象的类 ...
- C语言与MATLAB接口 编程与实例 李传军编着
罗列一下以前自己学习C语言与MATLAB混编的笔记,顺便复习一遍. <C语言与MATLAB接口 编程与实例 李传军编着>(未看完,目前看到P106) 目录P4-8 ************ ...
- 2018.3.5 Java语言基础与面向对象编程实践
Java语言基础与面向对象编程实践 第一章 初识Java 1.Java特点 http://www.manew.com/blog-166576-20164.html Java语言面向对象的 Java语言 ...
随机推荐
- [luogu3379]最近公共祖先(树上倍增求LCA)
题意:求最近公共祖先. 解题关键:三种方法,1.st表 2.倍增法 3.tarjan 此次使用倍增模板(最好采用第一种,第二种纯粹是习惯) #include<cstdio> #includ ...
- [poj3159]Candies(差分约束+链式前向星dijkstra模板)
题意:n个人,m个信息,每行的信息是3个数字,A,B,C,表示B比A多出来的糖果不超过C个,问你,n号人最多比1号人多几个糖果 解题关键:差分约束系统转化为最短路,B-A>=C,建有向边即可,与 ...
- 第一次WM_PAINT事件执行前显示白色框 的解决办法
界面显示前,总是会显示白色或白加黑的窗体, 开始以为是图片加载慢的原因,后来发现这个框是在第一次WM_PAINT执行前显示的. 解决办法很简单,在CreateWindow的时候,加上WS_POPUP样 ...
- 51NOD1835 完全图
传送门 分析 令f(i,j)表示i点完全图有j个联通块的方案数. 讨论有i-1个点已经固定了,我们拉出一个代表元素然后讨论它的集合大小然后组合数算一下就可以了. $$ dp(i,j) = \sum_{ ...
- 100851K King’s Inspection
传送门 题目大意 给你一张图,求这张图的汉密尔顿回路. 分析 因为m≤n+20,所以如果存在回路一定是在一个环中加入了至多20条边.我们先考虑dfs,但我们发现如果出现图1这种情况就会是复杂度爆炸 图 ...
- Luogu 3761 [TJOI2017]城市
BZOJ 4890. 在树上断开一条边之后会形成两个联通块,如果要使这一条边接回去之后保持一棵树的形态,那么必须在两个联通块之间各找一个点连接. 那么,对于每一条可能断开的边,它产生的答案是以下两者的 ...
- JavaWeb_增强for循环
引入增强for循环的原因:在JDK5以前的版本中,遍历数组或集合中的元素,需要先获得数组的长度或集合的迭代器,比较麻烦. JDK5中定义了一种新的语法----增强for循环,以简化此类操作.增强for ...
- SDUT 3377 数据结构实验之查找五:平方之哈希表
数据结构实验之查找五:平方之哈希表 Time Limit: 400MS Memory Limit: 65536KB Submit Statistic Problem Description 给定的一组 ...
- java的编码问题详解
ucenter的中文问题终于解决,这也暴露我对Java编码知识的严重不足,经过多次试验和搜索,对这块知识终于有了一个新的认识,所以把理解的内容写道这里 1:JVM的内存中字符串的编码格式是统一的吗? ...
- xml元素类型PCDATA和CDATA的区别(DTD中)
PCDATAPCDATA 的意思是被解析的字符数据(parsed character data).可把字符数据想象为 XML 元素的开始标签与结束标签之间的文本.PCDATA 是会被解析器解析的文 ...