The deal with multiple dispatch, as I understand it, is that instead of obj->somemethod, you define function named somemethod, which is defined for obj.
Maybe some other code calls it.
You can then define somemethod for other data types, without touching the original definition, and that makes your new definition available to the other code that used the original somemethod.
It is a unique feature of Julia (at least unique in a sense that it is absent from mainstream languages)
The thing that distinguishes multiple dispatch from single is that you can dispatch based on the types of all arguments to the method, not just one. E.g. you can define
function somemethod(x::Int, y::Int)
function somemethod(x::Int, y::Float64)
function somemethod(x::Float64, y::Float64)
Multiple dispatch is available at least in Common LISP, though I guess that's not considered particularly mainstream.
It's a form of function overloading, but works on runtime types. for example let's say we have a Dog and Cat, both subclass of Animal. And you define f(Cat, Dog), f(Animal, Animal). In languages without multiple dispatch, if you call it with a Cat object and a Dog object it will choose the first as expected, but if you pass with two Animal objects/pointers it will dispatch to the second regardless of what runtime values they are.
If the language is single dispatch though, animal1.f(animal2) will accurately call the Cat or Dog method for the first argument (before the dot), but the second argument will work like above, it will call the Animal version and not the Cat or Dog ones. If you want a method to call Cat or Dog method based on runtime information you'd have to redispatch on runtime within f(Animal), which is basically a pattern known as Visitor Pattern [1].
In Julia (and multiple dispatch languages) defining f(Cat, Dog) and f(Animal, Animal) means that even when I call f(animal1, animal2) the compiler will convert to the runtime values and if the first animal is Cat and the second is Dog it will call the first method (as a form of specialization) and otherwise it will go for f(Animal, Animal) (which is the more general method). And the Julia compiler is really good at inferring runtime types at compile time, so even though it's runtime values it's still static dispatch (that's why it's also fast).
You can think of it as similar to operator overloading. It's not quite the same, but it's a subtle distinction, or rather, the explanation of the difference is subtle.
You can find examples where operator overloading and multiple dispatch actually behaves differently and gives different answers, but the comparison works as a first order approximation.
Well, almost. Dispatch can happen at compile time, and in fact does for type-stable code. But the dispatch is on run-time types, not static types.
(The fact that you can have static dispatch on dynamic types is a pretty subtle point that hurts my head, but the upshot is that you get semantically dynamic dispatch with static performance as an optimization.)
You can then define somemethod for other data types, without touching the original definition, and that makes your new definition available to the other code that used the original somemethod. It is a unique feature of Julia (at least unique in a sense that it is absent from mainstream languages)